ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

驾驶员分心检测图像分类数据集:22,000张图像训练实践

驾驶员分心检测图像分类数据集:22,000张图像训练实践 简介面向计算机视觉与智能驾驶应用场景的驾驶员分心检测图像分类数据集包含约22,000张已标注图片覆盖安全驾驶、打电话、喝水、与乘客交谈等10类常见驾驶行为适合用于图像分类模型训练、算法评估以及相关课程设计。数据已按类别整理并划分训练集与测试集便于直接开展模型训练和精度验证同时提供json标注文件和show.py可视化脚本可直观查看各分类样本分布。资源包共2000个文件主体为1998张jpg格式图像另含1个Python脚本和1个json配置文件整体压缩包约649.16MB类型集中、结构清晰。当前已有69人学习下载适合自动驾驶辅助系统开发、驾驶员状态监测研究以及图像分类网络改进实验等场景。借助配套的CSDN博客专栏还可获得图像分类网络优化与计算机视觉完整项目的延伸思路。1. 驾驶员分心检测数据集22,000 张标注图像到底能做什么做车载视觉或者边缘设备上的行为识别最头疼的往往不是模型结构而是「有没有能用的数据」。公共分类数据集里人脸、物体一大堆但专门针对驾驶舱内驾驶员状态的图像分类数据集少得可怜而且很多标注质量参差不齐。这个标题指向的是一个已经标注好的图像分类数据集规模约 22,000 张覆盖驾驶员分心检测场景。拿到手之后你不需要自己翻视频抽帧、不需要手工画框或者打标签直接可以拿去训练图像分类模型快速验证算法选型和工程落地——这件事在真实项目里通常要耗费两周以上的人力。这个数据集适合三类人一是做车载安全预警系统的算法工程师需要快速迭代一个分心行为识别模型二是做边缘计算设备部署的同学想用轻量分类网络跑通端侧推理需要一个干净、标注统一的训练集三是高校或者研究团队做驾驶员行为分析、人机交互相关课题需要一个可复现的基准数据集。它解决的核心问题是「标注成本前置」让你把精力放在模型设计、训练策略和部署优化上而不是花时间整理数据。下面我会从数据内容、训练流程、参数调优和实际踩坑几个方面把这个数据集怎么用透讲清楚。2. 理解数据集构成22,000 张图像的分类体系与标注规范2.1 图像分类任务里这个数据集的标注维度怎么理解驾驶员分心检测在计算机视觉里通常有两个技术路线目标检测和图像分类。目标检测需要框出驾驶员的手、脸、手机等物体位置但标题明确写的是「图像分类数据集」意味着每一张图像整体被赋予一个类别标签模型要做的是「看到一张图判断它属于哪一类分心状态」。这个任务的特点是不需要定位只需要判别。在工程落地时图像分类模型往往作为第一级粗筛先把明显分心的帧挑出来再交给检测模型或者时序模型做进一步判断这样能显著降低端侧计算压力。常见的分类体系会把驾驶员状态划分为正常驾驶和若干分心类别例如打电话手持手机、发短信低头看手机、喝水、整理妆容、与乘客互动、操作中控台、后仰休息等。22,000 张图像分布在多个类别上每个类别的样本数量不可能完全均匀训练时要特别注意类别不均衡问题。数据集的标注规范一般会提前定义好类别 ID、图像命名规则和标签文件格式拿到数据后第一步不是直接训练而是先统计类别分布确认每个类有多少张图避免某个类别样本过少导致模型完全学不到特征。2.2 拿到数据集后的第一件事文件结构与标签格式检查无论数据集的原始格式是文件夹按类别组织还是 CSV / JSON 标注文件第一步都应该先写一个小脚本扫描全量数据。常见做法是import os from collections import Counter data_root path/to/driver_distraction_dataset # 假设目录结构是 train/类别名/图片.jpg train_dir os.path.join(data_root, train) class_counts Counter() for class_name in os.listdir(train_dir): class_path os.path.join(train_dir, class_name) if os.path.isdir(class_path): num_files len([f for f in os.listdir(class_path) if f.lower().endswith((.jpg, .jpeg, .png))]) class_counts[class_name] num_files print(f{class_name}: {num_files} 张) print(总样本数:, sum(class_counts.values()))这段代码的作用是统计每个类别的图像数量并校验目录结构是否符合预期。这里的data_root路径需要替换成你实际解压后的数据集路径。如果发现总样本数与简介中的 22,000 张对不上优先检查是不是有子目录嵌套或者非图片格式文件混入。另外一个值得注意的点是有些数据集会把训练集和验证集按比例预先划分好有些则只给一个全量大目录需要你自己划分。标题提到「约 22,000 张」这个「约」字意味着实际数量可能有几百张浮动这是正常的重点是确认类别完整度。2.3 标签文件解析从标注文件到 PyTorch / TensorFlow 可用的格式图像分类数据集的标签常见三种形式一是文件夹名即类别名二是 CSV 文件包含图像路径和类别 ID三是 JSON 文件包含映射关系。如果拿到的是 CSV解析方式非常直接import pandas as pd df pd.read_csv(labels.csv) print(df.head()) print(df[class_id].value_counts()) # 建立类别ID到名称的映射 class_names sorted(df[class_name].unique()) class_to_idx {name: idx for idx, name in enumerate(class_names)} print(class_to_idx)解析完成后建议把所有图像路径统一成绝对路径避免后续训练脚本因为工作目录不同而找不到文件。对于 PyTorch最省事的方式是直接用ImageFolder前提是目录结构恰好是root/类别/图像.jpg。如果不是这种结构就要自己写一个Dataset类。这里有一个容易忽略的细节图像的 EXIF 信息可能导致读取时方向不对尤其是手机拍摄的照片。如果数据集中混有带着旋转信息的 JPEG在数据加载时最好统一转换为 RGB 并固定方向否则同一个类别里会出现大量「横竖不一」的样本干扰模型学习。3. 基于 22,000 张图像训练分心检测分类模型从数据划分到训练脚本3.1 数据划分策略训练 / 验证 / 测试的比例与分层采样22,000 张图像说多不多说少不少。对于图像分类任务通常建议按 7:2:1 或者 8:1:1 划分训练、验证和测试集。但直接随机划分有一个隐患如果同一段视频的不同帧被分到训练集和验证集会造成数据泄露验证分数虚高。常见做法是按照「来源划分」——如果数据集来自多段视频最好把同一视频的帧全部放进同一个集合。但很多公开数据集的图像来源信息并不透明我们能做的退而求其次方案是先按文件名排序然后用随机种子做分层采样保证每个类别在三个集合中的比例一致。from sklearn.model_selection import train_test_split # df 包含 image_path 和 class_id 两列 X df[image_path].values y df[class_id].values # stratify 保证每个类别的样本比例在划分后保持一致 X_train, X_temp, y_train, y_temp train_test_split( X, y, test_size0.3, random_state42, stratifyy ) X_val, X_test, y_val, y_test train_test_split( X_temp, y_temp, test_size1/3, random_state42, stratifyy_temp ) print(f训练集: {len(X_train)}, 验证集: {len(X_val)}, 测试集: {len(X_test)})random_state42是固定随机种子保证每次运行划分结果一致方便对比实验。stratifyy是关键如果不加这个参数某些小类别可能全被分到训练集或验证集导致验证失去意义。划分完之后记得把三个集合的路径和标签分别保存成 CSV 文件后面训练脚本直接读表不用每次重新划分。3.2 数据增强让 22,000 张图像发挥出 50,000 张的效果分心检测数据的场景相对固定驾驶舱内部、驾驶员坐姿、光线变化有限。但这恰恰意味着数据增强要特别设计不能盲目使用随机裁剪和水平翻转。因为在真实场景中驾驶员可能在主驾驶位也可能在副驾驶位摄像头安装位置不同会导致左右镜像变化所以水平翻转是合理的。但垂直翻转绝对不能用因为驾驶员不可能倒着开车。PyTorch 里常用的增强组合如下from torchvision import transforms train_transforms transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomResizedCrop(224, scale(0.8, 1.0)), transforms.RandomHorizontalFlip(p0.5), transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2, hue0.05), transforms.RandomRotation(degrees5), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) val_transforms transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])这段代码里训练集用RandomResizedCrop做随机裁剪和缩放模拟驾驶员头部位置偏移RandomRotation(degrees5)的角度限制在 5 度以内因为真实驾驶场景中图像不会大角度旋转超过 15 度的旋转增强反而会引入不真实的样本。ColorJitter里的亮度、对比度调整是为了应对不同时间段的日照变化。注意验证集完全不做随机增强只做缩放和归一化保证验证结果的稳定性。一个常见的误区是数据增强力度越大越好。但在分心检测任务里过强的增强比如随机擦除、大幅旋转会让模型学到「假特征」尤其是在小数据集上增强带来的噪声可能超过收益。建议从轻度增强开始先跑通基线再逐个增加增强项观察验证集精度的变化。3.3 模型选择与训练脚本ResNet 还是 EfficientNet22,000 张图属于中小规模数据集在这个量级下从零训练一个深层 CNN 模型比如 ResNet-50很容易过拟合。常见做法是使用 ImageNet 预训练权重做迁移学习。分心检测的图像内容和 ImageNet 的自然图像差异较大但底层的边缘、纹理特征仍然通用所以冻结前几层、微调后面几层是性价比最高的方案。下面是一份可直接运行的 PyTorch 训练脚本骨架import torch import torch.nn as nn from torchvision import models from torch.utils.data import DataLoader, Dataset from PIL import Image import pandas as pd class DriverDataset(Dataset): def __init__(self, csv_file, transformNone): self.df pd.read_csv(csv_file) self.transform transform def __len__(self): return len(self.df) def __getitem__(self, idx): img_path self.df.iloc[idx][image_path] label self.df.iloc[idx][class_id] image Image.open(img_path).convert(RGB) if self.transform: image self.transform(image) return image, label # 模型使用预训练的 ResNet18把最后一层全连接改成类别数 model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) num_classes 10 # 根据实际类别数修改 model.fc nn.Linear(model.fc.in_features, num_classes) # 冻结除最后两层之外的所有层 for name, param in model.named_parameters(): if fc not in name and layer4 not in name: param.requires_grad False criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr1e-3)这里选择 ResNet18 而不是 ResNet50是因为 22,000 张数据不足以支撑更大模型的充分训练而且车载端侧设备的算力有限ResNet18 的参数量约 11M在嵌入式设备上更容易达到实时要求。layer4和fc层保留可训练其他层冻结既保留了 ImageNet 提取的通用特征又让高层特征适应分心检测的特定语义。优化器用 Adam 比 SGD 收敛更快适合快速验证如果想追求更高精度可以后期切换到 SGD momentum并配合余弦退火学习率。3.4 训练过程中的监控指标与早停策略训练分类模型不能只看 loss 曲线更要关注每个类别的准确率。在分心检测场景中正常驾驶类别的样本可能占 30% 以上而喝水、化妆这类细分类别占比很低整体准确率可能很高但小类别几乎全错。所以训练时要在每个 epoch 结束后计算混淆矩阵并保存每个类别的 recall 值。from sklearn.metrics import confusion_matrix, classification_report def evaluate(model, val_loader): model.eval() all_preds [] all_labels [] with torch.no_grad(): for images, labels in val_loader: outputs model(images) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.cpu().numpy()) print(classification_report(all_labels, all_preds, digits4)) return confusion_matrix(all_labels, all_preds)这个评估函数会打印每个类别的 precision、recall、f1-score比只看 top-1 accuracy 有用得多。如果你发现某个分心类别比如「发短信」的 recall 很低说明模型倾向于把它预测成别的类别这时候需要检查该类别的样本数是否太少或者该类别的图像与其他类别过于相似。训练时建议用早停验证损失连续 5 个 epoch 不下降就停止训练并保存验证集上 macro F1 最高的模型权重而不是最后一个 epoch 的权重。4. 用 YOLO 格式做检测不先把它当纯分类问题处理再决定是否升级4.1 为什么标题是「图像分类」而不是「目标检测」很多读者看到「驾驶员分心检测」第一反应是 YOLO、目标检测框、标注框。但这份数据集明确标注为「图像分类数据集」意味着它根本没有提供物体框的标注信息每张图只有一个整体标签。硬要用 YOLOv8 训练目标检测模型除非你再去手动标注所有物体的 bounding box否则此路不通。22,000 张图全部手工画框一个人至少需要 3 到 4 周的工作量这违背了这份数据集「标注前置」的初衷。正确思路是先用图像分类模型做帧级别的状态判断把一段驾驶视频逐帧分类得到每一帧的状态标签后再用时序平滑算法例如滑动窗口投票去除单帧抖动形成稳定的行为片段。这种做法在工业项目中非常常见因为分类模型占用资源少可以同时跑多个摄像头通道。如果业务上确实需要定位「手机在哪个位置」「手放在哪里」那才需要考虑检测模型并且额外准备一个带框标注的小规模数据集来做微调。4.2 分类模型输出如何落地到驾驶员分心预警系统一个完整的分心预警系统不是简单地把模型输出打印出来而是需要联动判定逻辑。模型输出的每个类别都对应一个风险等级例如「正常驾驶」是低风险「打电话」是中风险「发短信」「低头看手机」是高风险。系统级设计通常是这样的RISK_LEVEL { normal: 0, call_left: 1, call_right: 1, text_left: 2, text_right: 2, reach_behind: 2, drink: 1, adjust_radio: 1, talking: 1, look_back: 2 } def frame_decision(class_id, confidence, threshold0.7): if confidence threshold: return 0 # 置信度太低不触发报警 return RISK_LEVEL[class_id]这里的关键点是置信度阈值。图像分类模型的输出是 softmax 概率如果最大概率只有 0.4说明模型对当前帧的判断非常犹豫此时不应该触发预警。阈值的设定没有固定值需要通过验证集上 precision-recall 曲线来确定调低阈值会提高召回率但增加误报调高阈值则反之。对于驾驶员分心预警误报会严重干扰驾驶体验所以阈值通常设得偏高比如 0.7 到 0.8。另外一个工程细节是帧间去抖。单帧分类结果会出现「正常 → 打电话 → 正常」这样的高频抖动原因是驾驶员的动作幅度、遮挡、光照变化。最简单的去抖策略是滑动窗口投票取最近 10 帧的分类结果用出现次数最多的类别作为当前状态。如果窗口内两种状态各占一半则保持上一状态不变。这个策略效果明显实现成本极低比直接套用 LSTM 等时序模型更容易落地在边缘设备上不会增加推理延迟。4.3 从分类到检测的升级路径什么时候需要换路线在实际项目中甲方可能会加需求「我要知道手机具体出现在屏幕哪个位置。」这时候纯分类模型不满足要求需要升级到目标检测。但不要丢开现有数据集重头开始一个可靠的迁移路径是先训练好分类模型用分类模型对视频帧做预筛选只保留「分心」类别的帧然后在这些帧上人工标注检测框。这样一来需要标注的数据量大幅减少因为正常驾驶的帧不需要标注框。如果你打算直接用 YOLOv8 训练自己的检测数据集可以参考以下命令把图像分类的数据目录重新组织为检测格式# 把分类数据集按类别分目录复制到 images/ 目录 # 然后用 labelImg 或 LabelStudio 在 images/ 里画框 # 生成的标注文件保存为 YOLO 格式的 txt但这里要提醒用 YOLOv8 训练自己的数据集时标注格式和训练命令有很多细节坑。比如 YOLO 格式的标签文件里类别 ID 必须从 0 开始连续编号文本框坐标是归一化后的值0 到 1并且类别 ID 要与 data.yaml 里的 names 顺序保持一致。如果分类数据集的类别有 10 个但检测你只关心「手机」和「手」两个目标那么检测模型的类别数只有 2和分类模型的 10 个类别没有直接映射关系需要重新定义语义。5. 训练与部署中的避坑指南图像分类数据集的 5 个典型踩坑记录5.1 坑一样本不均衡导致模型偏向高频类别现象训练完后整体准确率有 92%但查看每个类别的 recall发现「正常驾驶」类别 recall 高达 99%而「喝水」「与乘客互动」等类别的 recall 只有 40% 左右。模型严重偏向训练集中样本数量多的类别。原因数据集中「正常驾驶」的帧数天然多于分心行为如果你直接使用CrossEntropyLoss每个样本的权重相同模型优化目标是整体准确率自然会牺牲小类别。解决计算每个类别的样本数为小类别赋予更高的 loss 权重。PyTorch 中可以直接给CrossEntropyLoss传入weight参数class_counts torch.tensor([10000, 3000, 2000, 1500, 1200, 1000, 800, 700, 600, 500], dtypetorch.float32) class_weights 1.0 / class_counts class_weights class_weights / class_weights.sum() * num_classes # 归一化 criterion nn.CrossEntropyLoss(weightclass_weights)使用加权 loss 之后小类别的梯度贡献变大模型会花更多精力学习这些类别的特征。不过注意权重不能设置得过大否则模型会把很多正常驾驶样本误判为分心行为造成更多误报。一般建议权重的最大值不超过最小权重类别的 5 倍。5.2 坑二图像尺寸不统一导致训练时报错或精度波动现象训练脚本报错Expected 3D tensor, got 2D或者训练过程 loss 持续震荡、验证集精度忽高忽低。原因数据集中混有灰度图单通道和 RGB 图三通道或者图像的宽高比例差异过大比如有 1920x1080 的横图也有 1080x1920 的竖图。分类模型输入通常需要固定尺寸比如 224x224如果不对原始尺寸做统一处理数据加载器会产生不一致的 tensor 形状。解决在Dataset的__getitem__里强制转 RGB并让训练集中的增强包含 Resize 操作。关键是先扫描数据集里有没有灰度图from PIL import Image import os gray_count 0 for root, dirs, files in os.walk(dataset_root): for f in files: if f.endswith(.jpg): img Image.open(os.path.join(root, f)) if img.mode ! RGB: gray_count 1 print(f非RGB图像: {os.path.join(root, f)} - {img.mode}) print(f总数: {gray_count})如果数据量只有几十张灰度图最简单的方式是在扫描之后统一用 PIL 转换。如果是有大量竖图横图混合建议在 Resize 之前先做短边填充而不是直接拉伸因为直接拉伸会把驾驶员的脸拉变形影响分类效果。通常做法是调整尺寸到 256x256中心裁剪或随机裁剪到 224x224而不是直接将 1920x1080 压缩成 224x224。5.3 坑三验证集和训练集数据泄露导致指标虚高现象验证集准确率高达 98%但部署到实际测试环境中只有 70% 左右的准确率差异极大。原因数据集制作者在整理数据时很可能把连续视频帧按顺序排列图像文件名相邻的样本内容高度相似。如果你按文件名顺序直接切分前 70% 作为训练集、后 30% 作为验证集那么训练集中包含了很多与验证集完全相同的场景、同一个人的相似动作模型相当于「记住」了这些样本而不是「学会」了判断分心状态。解决构建数据集时不能使用顺序切分。如果无法追溯每一帧的来源视频至少要在随机划分的基础上再做一步去重计算图像的感知哈希perceptual hash把相似度高于 0.95 的样本归为一组确保同一组的图像全部在训练集或全部在验证集中。这一步可以用一行命令式的 Python 实现from PIL import Image import imagehash def get_phash(img_path): return imagehash.phash(Image.open(img_path)) # 为每个样本计算 phash然后按相似度聚类 # 实际工程中如果数据量太大可以只对疑似连续的帧计算相似度这个方案的名字叫「感知哈希去重」是数据清洗中的常见做法。实际做的时候可以先对图像文件名排序只对相邻样本计算 phash 差异因为同一个视频的连续帧在排序后大概率相邻这样做计算成本可以接受。5.4 坑四训练集和真实场景光线分布不一致导致泛化差现象模型在数据集自带的测试集上表现不错但装到实车摄像头后白天逆光、夜间暗光场景下误报率飙升。原因数据集图像大多来自固定摄像头、固定时段拍摄光线分布集中。模型学习到的颜色和亮度特征在极端光照下失效比如夜间暗光图像噪点大模型会误判为「低头」。解决在数据增强中加入光照扰动模拟比如随机 Gamma 校正和噪声注入。Torchvision 里没有直接的 Gamma 增强可以通过torchvision.transforms.functional.adjust_gamma自定义import random import torchvision.transforms.functional as TF def gamma_adjust(img): gamma random.uniform(0.7, 1.5) return TF.adjust_gamma(img, gamma) # 将 gamma_adjust 加入 train_transforms另外可以考虑用灰度图跑一个副模型因为夜间彩色信息不可靠形状和纹理才是关键。也可以用 NVIDIA 的 DALI 库做 GPU 加速数据增强在训练时模拟更多夜间噪声。但根本解法还是采集一部分真实场景数据补充训练集这需要产品前期就考虑数据闭环。5.5 坑五类别 ID 映射混乱导致模型输出张冠李戴现象训练时 loss 正常下降验证集准确率也很高但部署后打印出来的类别名称和实际动作完全对不上比如把「正常驾驶」输出成「发短信」。原因数据集的类别 ID 映射可能改变了两次。源数据集的 CSV 里的class_id可能不是从 0 开始连续编号中间跳了几个数字或者类别顺序在你重新构建训练集时被打乱而最后部署时的映射表和模型训练时用的映射表不一致。解决从数据准备阶段就把类别映射表固化成 JSON 文件并在训练脚本和推理脚本中统一加载import json class_mapping { normal: 0, call_left: 1, call_right: 2, text_left: 3, text_right: 4, reach_behind: 5, drink: 6, adjust_radio: 7, talking: 8, look_back: 9 } with open(class_mapping.json, w) as f: json.dump(class_mapping, f, indent2) # 推理时 with open(class_mapping.json, r) as f: class_mapping json.load(f) # 模型输出的数字索引通过这个映射转换为类别名称这里最关键的教训是永远不要在代码里手写类别名和索引的对应顺序每次训练前从数据集的标签源自动生成映射并保存。修改数据集或新增类别时先检查映射文件而不是凭记忆改代码。这类「玄学」问题往往排查半天最后发现是映射表错了。6. 验证数据集效果的进阶方法混淆矩阵、t-SNE 与模型校准拿到数据集并完成训练之后不要满足于一个孤零零的 top-1 accuracy尤其是做工程交付时需要向团队或客户证明这个数据集可靠、模型可解释。我习惯做三件事第一件事是输出完整的混淆矩阵按行归一化让每个类别「最容易跟谁混淆」一目了然。比如「喝水」和「打电话」经常混淆因为手部靠近脸部的动作相似「整理妆容」和「与乘客互动」也可能混淆因为都存在头部偏转。看到具体的混淆关系就能反向指导数据增强和数据采集比如专门补充「手拿杯子靠近嘴」和「手拿手机靠近耳」的对比样本。第二件事是用 t-SNE 可视化最后一层特征向量。把验证集的图像输入模型提取 fc 层之前的 512 维特征然后用sklearn.manifold.TSNE降到二维按照类别标签着色。如果同一类别的点聚集在一起、不同类别的点彼此分离说明模型学到的特征区分度足够如果某个类别的点散落在其他类别中间大概率是样本本身多样性太大或者标注错误混入。这段代码在配合matplotlib的情况下很好实现但要注意 t-SNE 计算量大验证集 2,000 张图跑一次大约需要十几秒。如果特征点黏成一团说明模型欠拟合或者类别定义本身模糊需要回看数据标注规范。第三件事是模型校准。分类模型的 softmax 输出置信度并不等价于真实概率尤其在迁移学习微调后模型很容易过度自信或不够自信。可以用温度缩放做校准做法是在验证集上学习一个温度系数 T把模型输出的 logits 除以 T 再做 softmax。温度 T 大于 1 会让概率分布更平滑小于 1 会更尖锐。对于预警系统我们希望低置信度的误报被有效过滤所以合理校准非常重要import torch.nn.functional as F def calibrate_temperature(model, val_loader, init_t1.0): model.eval() logits_list [] labels_list [] with torch.no_grad(): for images, labels in val_loader: logits model(images) logits_list.append(logits) labels_list.append(labels) logits_all torch.cat(logits_list) labels_all torch.cat(labels_list) # 用优化器搜索最优 T使 NLL 最小 T torch.tensor(init_t, requires_gradTrue) optimizer torch.optim.LBFGS([T], lr0.01, max_iter50) def eval_nll(): optimizer.zero_grad() loss F.cross_entropy(logits_all / T, labels_all) loss.backward() return loss optimizer.step(eval_nll) return T.item()这段代码使用 LBFGS 优化器迭代求解温度 T注意 LBFGS 的step方式比较特殊需要传入闭包函数。温度校准之后你就可以设定更有意义的置信度阈值比如 0.8用于端侧预警。真实场景里的经验是校准后的置信度能减少约 30% 到 50% 的误报。最后还想补充一个我在实战中常用的习惯在训练结束后把验证集里被模型误判的样本单独抽出来看一遍做成一个「hard examples」文件夹。这些样本是改进模型和数据集的切入口有些标注本身可能就有问题有些是遮挡严重、光线极差的边缘情况。把这些图连同预测结果导入 LabelStudio 重新审查能发现数据集的标注上限在哪里——因为很多情况下图像分类数据集标注不一致才是模型精度上不去的根本原因而不是模型结构不够强。我通常会把误判样本按类别整理成子文件夹下次迭代训练时把它们加进训练集并配合更高的增强权重。这个流程看似原始但比盲目换模型有效得多。希望这些基于 22,000 张图像的实际经验能帮你在驾驶员分心检测这个方向上少走弯路。本文还有配套的精品资源点击获取
返回列表