CNN-BiLSTM+知识迁移:电动公交车分心驾驶检测框架

Int. J. Automotive Technology 论文解读

Zhao, Li, Fan et al., “A Distracted Driving Detection Framework for Electric Buses with Hybrid CNN-BiLSTM and Knowledge Transfer”, Int. J. Automot. Technol., 2026.

论文信息

项目 内容
标题 A Distracted Driving Detection Framework for Electric Buses with Hybrid CNN-BiLSTM and Knowledge Transfer
作者 Zhao D., Li H., Fan K. et al.
期刊 International Journal of Automotive Technology
年份 2026
DOI 10.1007/s12239-026-00538-3
场景 电动公交车(商用车辆)

核心创新

  1. CNN-BiLSTM混合架构:CNN提取空间特征 + BiLSTM建模时序依赖
  2. 知识迁移:从轿车数据迁移到公交车场景(跨域迁移)
  3. 电动车队场景:首个针对电动公交车的分心驾驶检测框架

为什么是电动公交车?

特点 轿车DMS 电动公交车DMS
驾驶时间 1-2小时 8-12小时
驾驶员 个体 职业驾驶员
数据量 大(量产) 小(车队有限)
场景 多样 固定路线
分心行为 手机/疲劳 手机/交谈/疲劳
痛点 — 数据少→需迁移

CNN-BiLSTM架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
"""
CNN-BiLSTM混合架构实现

CNN: 提取每帧的空间特征(面部关键点/姿态)
BiLSTM: 建模帧间时序依赖(行为序列)
注意力: 加权关键帧(如分心瞬间)

知识迁移:
1. 源域:轿车DMS数据(大量,如StateFarm/DDD数据集)
2. 目标域:电动公交车(少量)
3. 迁移策略:预训练CNN→微调BiLSTM
"""

import torch
import torch.nn as nn
from typing import Tuple

class CNNBiLSTMDistraction(nn.Module):
"""
CNN-BiLSTM分心驾驶检测框架

输入: 视频帧序列 (B, T, C, H, W)
输出: 分心类别概率 (B, n_classes)

参数: 可配置CNN骨干和LSTM隐藏维度
"""

def __init__(
self,
n_classes: int = 5,
cnn_backbone: str = "mobilenet_v3_small",
lstm_hidden: int = 256,
lstm_layers: int = 2,
dropout: float = 0.3,
):
super().__init__()
self.n_classes = n_classes

# CNN骨干(预训练,可从轿车数据迁移)
if cnn_backbone == "mobilenet_v3_small":
import torchvision.models as models
backbone = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights.DEFAULT)
self.cnn = nn.Sequential(*list(backbone.children())[:-1])
cnn_out = 576 # MobileNetV3-Small特征维度
else:
# 简化CNN
self.cnn = nn.Sequential(
nn.Conv2d(3, 32, 3, stride=2, padding=1), nn.ReLU(),
nn.Conv2d(32, 64, 3, stride=2, padding=1), nn.ReLU(),
nn.Conv2d(64, 128, 3, stride=2, padding=1), nn.ReLU(),
nn.AdaptiveAvgPool2d(1),
)
cnn_out = 128

# BiLSTM时序建模
self.lstm = nn.LSTM(
input_size=cnn_out,
hidden_size=lstm_hidden,
num_layers=lstm_layers,
batch_first=True,
bidirectional=True,
dropout=dropout if lstm_layers > 1 else 0,
)

# 注意力层
self.attention = nn.Sequential(
nn.Linear(lstm_hidden * 2, lstm_hidden),
nn.Tanh(),
nn.Linear(lstm_hidden, 1),
)

# 分类头
self.classifier = nn.Sequential(
nn.Linear(lstm_hidden * 2, 128),
nn.ReLU(),
nn.Dropout(dropout),
nn.Linear(128, n_classes),
)

def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
"""
Args:
x: (B, T, C, H, W) 视频帧序列
Returns:
logits: (B, n_classes) 分类结果
attention_weights: (B, T) 注意力权重
"""
B, T, C, H, W = x.shape

# CNN提取每帧特征
x = x.view(B * T, C, H, W)
features = self.cnn(x)
features = features.view(B, T, -1) # (B, T, D)

# BiLSTM时序建模
lstm_out, _ = self.lstm(features) # (B, T, 2*hidden)

# 注意力加权
attn_weights = self.attention(lstm_out) # (B, T, 1)
attn_weights = torch.softmax(attn_weights, dim=1)

# 加权求和
weighted = (lstm_out * attn_weights).sum(dim=1) # (B, 2*hidden)

# 分类
logits = self.classifier(weighted)

return logits, attn_weights.squeeze(-1)


class KnowledgeTransfer:
"""
知识迁移策略

源域: 轿车DMS数据集(大量)
目标域: 电动公交车数据(少量)

迁移方法: Fine-tuning with frozen CNN
1. 在源域数据上预训练CNN-BiLSTM
2. 冻结CNN,在目标域数据上微调BiLSTM
3. 可选:渐进式解冻CNN最后几层
"""

def __init__(self, model: CNNBiLSTMDistraction):
self.model = model

def stage1_pretrain(self, source_data, epochs=50):
"""Stage 1: 在轿车数据上预训练"""
print("Stage 1: 在源域(轿车)数据上预训练")
# 全参数训练
for param in self.model.parameters():
param.requires_grad = True
# ... 训练循环 ...

def stage2_finetune(self, target_data, epochs=20):
"""Stage 2: 在公交车数据上微调"""
print("Stage 2: 在目标域(公交车)数据上微调")

# 冻结CNN
for param in self.model.cnn.parameters():
param.requires_grad = False

# 仅训练BiLSTM+注意力+分类头
trainable = [
p for p in self.model.parameters() if p.requires_grad
]
print(f" 可训练参数: {sum(p.numel() for p in trainable):,}")
print(f" 冻结参数: {sum(p.numel() for p in self.model.cnn.parameters()):,}")

def stage3_progressive_unfreeze(self, target_data, epochs=10):
"""Stage 3: 渐进式解冻CNN最后层"""
print("Stage 3: 渐进式解冻")
# 解冻CNN最后1-2层
for param in list(self.model.cnn.parameters())[-4:]:
param.requires_grad = True


# ==================== 测试 ====================
if __name__ == "__main__":
# 模型初始化
model = CNNBiLSTMDistraction(
n_classes=5,
cnn_backbone="simple", # 测试用简化CNN
lstm_hidden=128,
lstm_layers=2,
)

total_params = sum(p.numel() for p in model.parameters())
print(f"=== CNN-BiLSTM分心检测模型 ===")
print(f"总参数: {total_params:,}")

# 模拟输入
batch_size = 4
seq_len = 30 # 1秒@30fps
x = torch.randn(batch_size, seq_len, 3, 64, 64)

# 前向
logits, attn = model(x)
print(f"\n输入: {x.shape} (B, T, C, H, W)")
print(f"输出: {logits.shape} (B, n_classes)")
print(f"注意力: {attn.shape} (B, T)")

# 分心类别
classes = ['正常驾驶', '手机使用', '交谈分心', '疲劳', '其他']
probs = torch.softmax(logits, dim=-1)
for i in range(batch_size):
pred = classes[probs[i].argmax()]
conf = probs[i].max().item()
print(f" 样本{i}: {pred} ({conf:.1%})")

# 知识迁移
print(f"\n=== 知识迁移策略 ===")
transfer = KnowledgeTransfer(model)
transfer.stage1_pretrain(None)
transfer.stage2_finetune(None)
transfer.stage3_progressive_unfreeze(None)

print(f"\n=== 商用车辆DMS特殊性 ===")
print(f" 轿车DMS: 个体驾驶、多样场景、大量数据")
print(f" 公交DMS: 职业驾驶员、固定路线、少量数据")
print(f" 迁移价值: 轿车数据预训练→公交场景微调")
print(f" 挑战: 摄像头位置不同、驾驶员坐姿不同、光照不同")

分心类别与Euro NCAP映射

分心类别 CNN-BiLSTM检测 Euro NCAP场景 告警等级
手机使用 ✅ 手持至耳边 D-02/D-03 一级
交谈分心 ✅ 头部转向乘客 D-05 (视线偏离) 二级
疲劳 ✅ 打哈欠+闭眼 F-01 (PERCLOS) 一级/二级
其他 ✅ 喝水/吸烟等 — —
正常 ✅ 基线 — 无

知识迁移的挑战

迁移维度 轿车→公交车 难度
摄像头位置 后视镜→挡风玻璃顶部 ⚠️ 中
驾驶员坐姿 轿车座椅→公交车座椅 ⚠️ 中
光照条件 多样→公交车固定路线 ✅ 低
驾驶员外观 多样→职业驾驶员群体 ⚠️ 中
分心行为 手机→交谈(公交车常见) 🔴 高

核心挑战: 公交车驾驶员分心行为与轿车不同——交谈在公交上是常态而非分心。

IMS开发启示

1. 商用车辆DMS需求

车辆类型 DMS需求 数据 迁移价值
乘用车 标准 大量 源域
电动公交车 8-12h驾驶 小 ✅ 迁移
货车 长途疲劳 小 ✅ 迁移
出租车 城市分心 中 ⚠️ 部分
网约车 个体+导航 中 ⚠️ 部分

2. 时序建模的重要性

1
2
3
4
5
6
7
8
9
10
11
# 单帧vs序列
# 单帧CNN: 只看当前状态→容易误判
# CNN-BiLSTM: 看序列→区分"看手机"vs"低头拿东西"

# 时序窗口选择
window_options = {
'0.5s (15帧)': '太短,无法区分短暂动作',
'1.0s (30帧)': '平衡,推荐',
'2.0s (60帧)': '更准但延迟增加',
'5.0s (150帧)': '疲劳检测需要,但分心检测过长',
}

3. 部署优先级

功能 模型 参数 延迟 优先级
分心检测 CNN-BiLSTM ~2M ~50ms P0
疲劳检测 PERCLOS+EAR <1K <1ms P0
手机检测 CNN单帧 ~1M ~10ms P1
行为序列 BiLSTM ~500K ~20ms P1

局限性

  1. 公交车特定:场景可能不适用于所有商用车辆
  2. 跨域迁移gap:轿车→公交车存在摄像头/坐姿差异
  3. 交谈分心:公交车交谈是常态,需重新定义
  4. BiLSTM计算量:比纯CNN大,需优化部署
  5. 数据集依赖:知识迁移效果取决于源域数据质量

结论

CNN-BiLSTM+知识迁移为商用车辆DMS提供了可行路径:

  1. 时序建模必要——单帧CNN无法可靠区分分心行为
  2. 知识迁移解决数据稀缺——轿车预训练→公交微调
  3. 商用车辆DMS需求独特——8-12h驾驶+职业驾驶员
  4. 注意力机制增加可解释性——可知道哪些帧触发了判定

对IMS的启示:商用车辆DMS不应直接复用乘用车方案,但可通过迁移学习快速适配。


参考来源:

  • Zhao et al., Int. J. Automot. Technol., 2026, DOI: 10.1007/s12239-026-00538-3
  • MobileNetV3 (Howard et al., 2019)
  • BiLSTM时序建模 (Graves & Schmidhuber, 1997)
  • 知识迁移 (Pan & Yang, 2010)