基于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/10/7 9:34:47 阅读更多 →
免费AI写歌软件推荐|AI写歌软件怎么选,哪些更适合做完整中文歌

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

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

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

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

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

2026/10/10 12:09:57 阅读更多 →

最新新闻

emoji 图片与编码表维护指南:从豆腐块到精准匹配

emoji 图片与编码表维护指南:从豆腐块到精准匹配

简介:这份资源面向移动端开发者、前端工程师及文本处理研究者,系统整理了emoji表情的图形素材与编码对照数据,帮助解决跨平台表情显示异常、编码转换与数据库存储等实际问题。压缩包共468个文件,以467张png图片和1个sql数据库文件…

2026/10/15 13:03:27 阅读更多 →
context-mode详解:SQLite FTS5上下文感知搜索的核心开关

context-mode详解:SQLite FTS5上下文感知搜索的核心开关

1. “context-mode”到底是什么?别被术语唬住,它其实是开发者日常绕不开的“上下文感知开关”最近在好几个技术群和开源项目讨论区里,“context-mode”这个词高频出现,尤其和MCP、SQLite、FTS5这些词绑在一起。很多人第一反应是&a…

2026/10/15 13:03:27 阅读更多 →
AI Agent时代的能力单元:skills的本质是可验证的运行时契约

AI Agent时代的能力单元:skills的本质是可验证的运行时契约

1. “skills”不是功能菜单,而是AI Agent时代的底层能力契约最近在好几个技术群和开源项目讨论区里,看到大量开发者反复刷屏“skills”这个词——不是问“怎么学技能”,而是盯着终端里一行报错发呆:“npx claude/skills install报…

2026/10/15 13:03:27 阅读更多 →
RTD2660驱动板点屏实战:从原理图、固件到LVDS屏参调试

RTD2660驱动板点屏实战:从原理图、固件到LVDS屏参调试

简介:这份RTD2660资料大全面向嵌入式开发工程师、显示器驱动板维修人员及电子爱好者,整合了从本站多个RTD2660资料包中筛选出的程序原理图与源码资源,可解决芯片开发中原理理解、驱动编写与调试排错等实际问题。压缩包共746个文件、约30.08MB…

2026/10/15 13:03:27 阅读更多 →
CLI工具开发入门:从零构建可发布命令行应用

CLI工具开发入门:从零构建可发布命令行应用

我无法根据当前输入生成符合要求的博文。原因如下:项目标题 "impeccable" 本身是一个英文形容词(意为“无可挑剔的、完美的”),但未指明具体对象或领域。它既非技术名词、工具名、协议名,也非产品代号或项目…

2026/10/15 13:03:27 阅读更多 →
C4D插件Octane 4.0 RC7上手指南:安装、调参与避坑

C4D插件Octane 4.0 RC7上手指南:安装、调参与避坑

简介:面向C4D用户的OctaneRender 4.0 RC7渲染器资源包,覆盖C4D R15至R20等主流版本,专为需要GPU加速、实时预览和照片级输出的设计师打造。压缩包共605个文件,内含184张png贴图、164个res资源文件、80个str字符串、78个h头文件与6…

2026/10/15 13:02:27 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式: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/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →