用 1484 张真实路口照片训练交通信号灯识别模型:TensorFlow 实战笔记
【免费下载链接】mit-deep-learningTutorials, assignments, and competitions for MIT Deep Learning related courses.项目地址: https://gitcode.com/gh_mirrors/mi/mit-deep-learning
mit-deep-learning 仓库里藏着一套少见的"小数据真照片"分类任务:tutorials_previous/5_tensorflow_traffic_light_images/下的 1484 张真实路口信号灯特写,配上5_tensorflow_traffic_light_classification.ipynb里一个手写的 3 层卷积网络。跟着跑通,你会亲手搭出一个能分对红黄绿三色灯、并输出混淆矩阵的交通信号灯识别模型——全程不到 500 行代码。
MIT 驾驶数据集中的城市路口实拍:远处杆上的信号灯就是分类任务的识别对象
先搞清你的数据:三类照片,三类麻烦
在动手写模型之前,先把数据翻一遍,很多"模型效果不好"其实根源在数据上。
数据集就是三个按类别命名的子文件夹,red/、green/、yellow/,共1484 张真实场景照片:
| 类别 | 张数 | 说明 |
|---|---|---|
| red | 904 | 红灯特写,数量最多 |
| green | 536 | 绿灯特写 |
| yellow | 44 | 黄灯特写,严重偏少 |
三件事需要提前知道:
- 尺寸不统一:单张图从约 18×33 到 111×214 像素不等,是相机裁剪后的"灯头特写",不是完整路口照片,所以统一 resize 到 32×32 是必须的预处理步骤;
- 类别严重不均衡:yellow 只有 44 张,不到 red 的 5%。分类模型天然会偏向大类,后面评估时重点盯它;
- 代码是 TensorFlow 1 风格:Notebook 用了
tf.placeholder、sess.run这类 TF1 会话式 API,直接在 TensorFlow 2.x 下跑会报错,这一点下面"踩坑清单"里展开。
先 clone 仓库拿到数据:
git clone https://gitcode.com/gh_mirrors/mi/mit-deep-learning cd mit-deep-learning/tutorials_previous数据怎么喂进网络:32 像素、one-hot 与 90/10 切分
数据加载的核心就三件事,代码不到 15 行:
# 按"文件夹名即类别"加载,统一缩放到网络输入尺寸 for im_type in image_types: # ["red", "green", "yellow"] for ex in glob.glob(os.path.join(base_image_path, im_type, "*")): im = cv2.imread(ex) im = cv2.resize(im, (32, 32)) # 输入必须固定为 32x32 one_hot_array = [0] * len(image_types) one_hot_array[image_types.index(im_type)] = 1 # one-hot 标签 full_set.append((im, one_hot_array, ex)) random.shuffle(full_set) # 打乱顺序,避免同类扎堆影响 mini-batch几个值得留意的细节:
- one-hot 标签:3 类就编码成
[1,0,0]这样的向量,顺序固定为 red / green / yellow。预测时取 softmax 概率最大的下标,再映射回image_types里的名字; - 切分与截断:数据按
train_test_split_ratio = 0.9切成 90% 训练、10% 测试。切完 Notebook 还会把两个集合各截掉"不足一个 batch 的尾巴",保证每轮 epoch 的 batch 数量是整数——这个做法很实用,1484 张里有约 100 张因此没参与训练; - shuffle 不能省:如果按文件夹顺序加载,前 904 个全是红灯,mini-batch 梯度方向会被单一类别带偏,打乱后每个 batch 都混合三类,梯度估计才稳定。
模型配方:3 层卷积 + 1e-4 学习率,为什么够用
完整网络结构一览:
| 组件 | 配置 | 取值理由 |
|---|---|---|
| 输入 | 32×32×3 | 信号灯头部细节足够 32 像素承载 |
| 卷积 ×3 | 3×3 卷积,各 16 个滤波器,ReLU 激活 | 浅网络 + 少滤波器,刻意压低参数量防过拟合 |
| 池化 | 2×2 最大池化一次 | 压缩特征图,降低后面全连接层规模 |
| 输出 | 全连接层 → 3 维 logits + softmax | 三分类标准收尾 |
| 优化器 | Adam,学习率 1e-4 | 小网络小数据集,保守学习率收敛更平稳 |
| batch_size | 32 | 1484 张下兼顾梯度噪声与吞吐 |
| max_epochs | 25 | 经验值:小网络多数在第 10 个 epoch 前已收敛 |
# 三个同构的 3x3 卷积层串起来,滤波器数保持 16 不扩张 W_conv1 = weight_variable([3, 3, 3, 16]) b_conv1 = bias_variable([16]) h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1, 1) + b_conv1) # W_conv2 / W_conv3 结构相同,输入通道从 16 接 16损失函数用softmax_cross_entropy_with_logits,训练循环里每轮算一次全量训练 loss 和验证 loss,验证 loss 每刷新一次新低就存一份 checkpoint——等于自带早停,训练结束直接加载最优权重而不是最后一个。
⚠️ 踩坑清单:这四个雷几乎人人会踩
- TensorFlow 2.x 直接报错。
tf.placeholder、sess.run、tf.initialize_all_variables在 TF2 中已移除。现象:第一行代码就抛AttributeError。解法:装 TensorFlow 1.x 运行,或花半小时把会话式代码改写为 TF2 的函数式 / Keras 写法(模型逻辑完全不变)。 cv2.resize的参数顺序。第二参数是(width, height),和很多库的(height, width)相反。写反了图会被拉成横图,分类照样能跑但特征全歪。解法:resize 后加一句assert(im.shape == (32, 32, 3))做形状自检。- yellow 类被大面积误判。44 张黄灯对 904 张红灯,不均衡会让模型倾向把黄灯判成红或绿——现象是混淆矩阵对角线上 yellow 一格明显偏低,非对角线
yellow→red偏大。解法:按类别频率给 loss 加权、对 yellow 做复制增强,或干脆先接受"红绿高准、黄灯兜底"的指标预期。 - 测试集变少没察觉。为凑整 batch_size 截掉尾巴后,训练集约少 97 张、测试集约少 9 张。写自动化脚本时用
len(train_x)而不是"文件夹文件总数"当分母,否则算出来的准确率分母就不对。
怎么判断模型好坏:读混淆矩阵 + 一张进阶路线图
Notebook 最后两步值得照抄:先把测试集里判错的原图逐张打出来——直观看到模型在哪些光照、哪些角度翻车;再用sklearn.metrics.confusion_matrix画归一化混淆矩阵,对角线数值就是各类准确率,非对角线告诉你错误往哪个方向偏(结合上一节第 3 条一起看)。
分类只是入场券,真正的自动驾驶任务在"从完整画面里找到灯"。仓库里正好有两条现成的进阶路:
tutorial_driving_scene_segmentation/教程用 DeepLab 对驾驶视频做像素级语义分割,连远处信号灯都能被框出
- 从分类升级到检测:本任务是"给灯、判色",下一步是"给路口、找灯",可用 YOLO / SSD 类检测器复用这套数据做标注;
- 从分类到语义分割:仓库的 tutorial_driving_scene_segmentation/ 用 DeepLab 在 MIT Driving Scene Segmentation 数据集上做像素级分割,是同一批真实驾驶数据的另一种用法;
- 换更强的骨干网:把 3 层手写 CNN 换成预训练 ResNet 微调,重点看 yellow 类准确率能否从混淆矩阵里救回来。
下一步你可以做什么
三个当天就能动手的起点:把max_epochs从 25 加到 50,画 loss 曲线看收敛是否提前(Notebook 已内置 train/val 双线 plot);给 yellow 类做翻转 / 亮度增广,对比混淆矩阵变化;或者干脆把这套代码移植到 TensorFlow 2,当一次 API 迁移练习。数据集小、任务边界清晰,正是练手调参的好地方。
【免费下载链接】mit-deep-learningTutorials, assignments, and competitions for MIT Deep Learning related courses.项目地址: https://gitcode.com/gh_mirrors/mi/mit-deep-learning
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考