当前位置: 首页 > news >正文

基于CNN-LSTM优化模型的车辆路面类型识别实战:从数据修复到99.71%准确率

模型、GPU(RTX 5060)、数据加载全部正常工作。让我用完整数据做一个小规模端到端测试确认整套流程: ● Bash(cd "D:/huaweidata" && python -c " import importlib.util, warnings, numpy as np…) ⎿ ✅ 运行设备: cuda ✅ 显卡: NVIDIA GeForce RTX 5060 📊 总时序点数: 865605 … +13 lines (ctrl+o to expand) ⎿ (timeout 2m) Thought for 2s (ctrl+o 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(新增 k=3 提取细粒度特征) │ ├────────────┼───────────────────┼──────────────────────────────────────────┤ │ 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(k=3) 提取更细粒度特征 启用通道注意力(原 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(f"Unknown 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_name=sheet) # 确保列名统一 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_index=True) print(f"📊 总时序点数: {len(merged_df)}") print(f"📊 路面类型数: {merged_df['label'].nunique()} (沥青/湿滑)") return merged_df ===================== 2. 数据增强(保留物理意义) ===================== def augment_vibration_window(window_xyz: np.ndarray, noise_std=0.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, size=window_xyz.shape) aug += noise # (3) 时间循环移位(模拟不同相位) shift = np.random.randint(-int(n_points * 0.05), int(n_points * 0.05)) aug = np.roll(aug, shift, axis=0) # (4) 时间反转(一半概率),对振动信号合理 if np.random.random() > 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() > 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 < 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, dtype=np.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, reduction=8): super().init() self.fc = nn.Sequential( nn.AdaptiveAvgPool1d(1), nn.Flatten(), nn.Linear(channels, max(channels // reduction, 4)), nn.ReLU(inplace=True), 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(k=3) → 提取细粒度局部振动模式 - 通道注意力(SENet)→ 自适应重标定特征通道 - 第一层 LSTM 改为双向 → 同时看前后上下文 - 分类头加 BatchNorm → 稳定训练 """ def __init__(self, input_dim=3, num_classes=2): super().__init__() # ----- Conv 特征提取模块 ----- self.conv_block1 = nn.Sequential( nn.Conv1d(input_dim, 96, kernel_size=15, padding="same"), nn.BatchNorm1d(96), nn.ReLU(inplace=True), nn.MaxPool1d(3), nn.Dropout(0.2), ) self.conv_block2 = nn.Sequential( nn.Conv1d(96, 160, kernel_size=7, padding="same"), nn.BatchNorm1d(160), nn.ReLU(inplace=True), nn.MaxPool1d(2), nn.Dropout(0.25), ) # 新增第三层:小卷积核提取精细特征 self.conv_block3 = nn.Sequential( nn.Conv1d(160, 160, kernel_size=3, padding="same"), nn.BatchNorm1d(160), nn.ReLU(inplace=True), nn.MaxPool1d(2), nn.Dropout(0.3), ) # 通道注意力 self.channel_attn = ChannelAttention(160, reduction=8) # ----- LSTM 时序建模模块 ----- self.lstm1 = nn.LSTM( input_size=160, hidden_size=128, batch_first=True, bidirectional=True, ) self.drop_lstm1 = nn.Dropout(0.35) self.lstm2 = nn.LSTM( input_size=256, hidden_size=96, # 双向 → 256 batch_first=True, bidirectional=False, ) self.drop_lstm2 = nn.Dropout(0.35) # ----- 分类头 ----- self.classifier = nn.Sequential( nn.Linear(96, 128), nn.BatchNorm1d(128), nn.ReLU(inplace=True), 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, patience=20, min_delta=1e-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 < 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 >= 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="训练损失", linewidth=1.5) plt.plot(val_loss, label="验证损失", linewidth=1.5) plt.title("损失曲线", fontsize=13, fontweight="bold") plt.xlabel("Epoch") plt.ylabel("Loss") plt.legend() plt.grid(True, alpha=0.3) plt.subplot(1, 2, 2) plt.plot(train_acc, label="训练准确率", linewidth=1.5) plt.plot(val_acc, label="验证准确率", linewidth=1.5) plt.title("准确率曲线", fontsize=13, fontweight="bold") plt.xlabel("Epoch") plt.ylabel("Accuracy") plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.savefig(save_path, dpi=150, bbox_inches="tight") print(f"📈 训练曲线已保存: {save_path}") plt.close() def plot_confusion_matrix(cm, class_names, save_path): plt.figure(figsize=(8, 6)) sns.heatmap( cm, annot=True, fmt="d", cmap="Blues", xticklabels=class_names, yticklabels=class_names, annot_kws={"size": 14}, ) plt.title("路面识别混淆矩阵 (CNN-LSTM)", fontsize=14, fontweight="bold") plt.xlabel("预测标签", fontsize=12) plt.ylabel("真实标签", fontsize=12) plt.tight_layout() plt.savefig(save_path, dpi=150, bbox_inches="tight") 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_size=0.2, random_state=42, stratify=y_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_size=BATCH_SIZE, shuffle=True, drop_last=False, num_workers=0, pin_memory=True, ) test_loader = DataLoader( test_set, batch_size=BATCH_SIZE * 2, shuffle=False, num_workers=0, pin_memory=True, ) # ---- 5. 模型初始化 ---- print("\n[4/6] 构建模型...") model = CNNLSTM_IMU(input_dim=3, num_classes=num_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. 损失函数 & 优化器 ---- # 类别权重:平衡沥青(多)与湿滑(少) class_weights = compute_class_weight( "balanced", classes=np.unique(y_encoded), y=y_encoded, ) class_weights = torch.tensor(class_weights, dtype=torch.float32).to(DEVICE) print(f"类别权重: {class_weights}") criterion = nn.CrossEntropyLoss(weight=class_weights) optimizer = optim.AdamW( model.parameters(), lr=LEARNING_RATE, weight_decay=WEIGHT_DECAY, ) # CosineAnnealingWarmRestarts:每个周期先升后降,帮助跳出局部最优 scheduler = CosineAnnealingWarmRestarts( optimizer, T_0=15, T_mult=2, eta_min=1e-6, ) early_stopper = EarlyStopping(patience=PATIENCE_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_blocking=True) batch_y = batch_y.to(DEVICE, non_blocking=True) 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(dim=1) 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_blocking=True) batch_y = batch_y.to(DEVICE, non_blocking=True) output = model(batch_x) loss = criterion(output, batch_y) val_loss += loss.item() pred_class = output.argmax(dim=1) 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( f"Epoch {epoch:3d}/{EPOCHS} | " f"Train Loss: {avg_train_loss:.4f} | Val Loss: {avg_val_loss:.4f} | " f"Train Acc: {train_acc:.4f} | Val Acc: {val_acc:.4f} | " f"LR: {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, dim=1) preds = output.argmax(dim=1) 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_names=classes_, digits=4, zero_division=0, )) # 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_division=0, ) 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], device='cuda: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 沥青: Precision=0.9981, Recall=0.9981, F1=0.9981, Support=534 湿滑: Precision=0.9937, Recall=0.9937, F1=0.9937, Support=158 📊 混淆矩阵已保存: confusion_matrix.png 📈 训练曲线已保存: training_history.png ✅ 训练完成!

准确率:99.71%

http://www.jsqmd.com/news/1239697/

相关文章:

  • 2026深圳靠谱装修公司**本地正规装企避坑与实测名单 - 优企甄选
  • OpenClaw技能生态解析与20个必装Skills推荐
  • 实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
  • 2026 年新发布:牙克石专业的防渗膜供货厂家深度解析与优选指南,装修漏水黑洞?这个膜帮你彻底告别渗漏! - 行业鉴选官
  • 构建交互式推理系统:从数据模型到推理引擎的实践指南
  • 虚拟歌手60fps高清MV制作:技术实现与本地部署全解析
  • 2026 郑州靠谱搬家公司甄选|全城各区适用,4 家本土直营品牌,告别低价套路 - 达海
  • LangChain4j与提示词工程:Java大模型开发实战
  • 笔记本电脑开关机策略:硬件寿命、能耗与使用场景全解析
  • 关于我从零写一个 C++ 分布式 KV 存储系统原型
  • 最好用的AI文献综述工具推荐:高效助力科研写作的实用工具盘点
  • PDFMathTranslate:突破PDF翻译限制,实现精准页面自由选择
  • WPS AI文档对比能力全拆解(企业法务与学术评审必藏版):实测准确率98.7%,误判率低于0.3%的校验逻辑首次公开
  • 2026 年至今,伽师可靠的聚醚回收公司推荐几家,扔掉旧物还能赚回钱?聚醚回收的秘密 - 企业推荐管【认证】
  • 千川素材库越来越乱,想找片段翻半天怎么办
  • 重磅!江诗丹顿宁波**网点2026年7月最新地址及客户热线通知 - 江诗丹顿服务中心
  • 衢州甲醛检测公司怎么选:只做检测不除醛的专业CMA资质实验室——国慷测研CMA甲醛检测及公共卫生检测 - CMA甲醛检测中心
  • 龙石数据团建|AI 数据中台4.0预发布,质量平台社区版安装突破100套!
  • C++编程入门:从十进制转二进制理解计算机数据表示与算法设计
  • 分布式日志架构与Kafka性能调优实战
  • 二代高通量测序公司推荐-伯远生物
  • 纪录片预告片制作技术全解析:从素材处理到多平台输出
  • 腾讯通RTX与勤哲Excel服务器集成实战指南
  • 视频太长看不完?用AI自动生成逐字稿+思维导图,一小时视频十分钟消化
  • AI作词工具与歌词生成器实测分享:写词卡壳时用来找灵感的实用工具
  • 真力时中国**售后服务中心|完整**热线和详细地址**信息通告(2026年7月更新) - 亨得利官方服务中心
  • 亲身到店探访长沙亨得利**名表服务中心|全新服务电话及详细维修地址(2026年7月更新) - 亨得利官方
  • 别再盲试!2024最值得投入的AI视频工具只有3款(基于200+小时生成日志与专业剪辑师盲测结果)
  • 2026甄选:重庆到鞍山物流专线,时效稳定与整车零担全覆盖的行业** - 甄选服务推荐
  • NET CORE 认证模块-注册方案与请求认证探究