1. 基于CNN的端到端车道保持模型构建
任务说明
本案例使用开源模拟器(如Udacity自驾驶模拟器或donkeycar模拟器)采集的“前视摄像头图像 + 对应转向角”数据,训练一个轻量级CNN回归模型。模型输入为单张RGB图像(66×200×3),输出为连续转向角(弧度)。训练完成后,将模型权重保存为lane_keeping_cnn.h5,并给出离线验证脚本,通过测试集计算预测转向角与真实转向角的均方根误差(RMSE),以此判定模型是否具备车道保持能力。
数据准备
本案例使用公开的模拟器数据集格式:每行记录包含图像文件路径和转向角。请将数据按8:1:1划分为训练集、验证集、测试集,并确保图像尺寸统一缩放为66×200。若本地无数据集,可先使用generate_dummy_data.py生成20张纯色合成图像及对应随机转向角,用于验证代码流程可运行。
模型结构(NVIDIA CNN变体)
输入层: 66×200×3
归一化层: Lambda(lambda x: x/127.5 - 1.0)
卷积层1: 24个5×5卷积核, stride=2, ReLU
卷积层2: 36个5×5卷积核, stride=2, ReLU
卷积层3: 48个5×5卷积核, stride=2, ReLU
卷积层4: 64个3×3卷积核, stride=1, ReLU
卷积层5: 64个3×3卷积核, stride=1, ReLU
展平层
全连接层1: 100神经元, ReLU, Dropout(0.5)
全连接层2: 50神经元, ReLU, Dropout(0.5)
输出层: 1神经元, 线性激活
代码实现
# train_lane_keeping.py
import os
import cv2
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, Lambda, Cropping2D
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
IMG_HEIGHT, IMG_WIDTH = 66, 200
def load_data(csv_path):
df = pd.read_csv(csv_path)
images, angles = [], []
for _, row in df.iterrows():
img = cv2.imread(row['image_path'])
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (IMG_WIDTH, IMG_HEIGHT))
images.append(img)
angles.append(float(row['angle']))
return np.array(images), np.array(angles)
def build_model():
model = Sequential([
Lambda(lambda x: x / 127.5 - 1.0, input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
Conv2D(24, (5,5), strides=(2,2), activation='relu'),
Conv2D(36, (5,5), strides=(2,2), activation='relu'),
Conv2D(48, (5,5), strides=(2,2), activation='relu'),
Conv2D(64, (3,3), activation='relu'),
Conv2D(64, (3,3), activation='relu'),
Flatten(),
Dense(100, activation='relu'),
Dropout(0.5),
Dense(50, activation='relu'),
Dropout(0.5),
Dense(1)
])
model.compile(optimizer=Adam(learning_rate=0.0001), loss='mse', metrics=['mae'])
return model
if __name__ == '__main__':
# 若使用真实数据,请将CSV路径指向实际文件
X, y = load_data('driving_log.csv')
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.2, random_state=42)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
model = build_model()
checkpoint = ModelCheckpoint('lane_keeping_cnn.h5', monitor='val_loss', save_best_only=True)
early_stop = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)
model.fit(X_train, y_train, validation_data=(X_val, y_val),
epochs=20, batch_size=64, callbacks=[checkpoint, early_stop], verbose=1)
# 保存最终模型
model.save('lane_keeping_cnn_final.h5')
np.save('X_test.npy', X_test)
np.save('y_test.npy', y_test)
print('训练完成,模型已保存。')
离线验证脚本
# evaluate_model.py
import numpy as np
import cv2
from tensorflow.keras.models import load_model
from sklearn.metrics import mean_squared_error
model = load_model('lane_keeping_cnn.h5')
X_test = np.load('X_test.npy')
y_test = np.load('y_test.npy')
predictions = model.predict(X_test)
rmse = np.sqrt(mean_squared_error(y_test, predictions))
mae = np.mean(np.abs(y_test - predictions))
print(f'测试集样本数: {len(X_test)}')
print(f'RMSE: {rmse:.4f}')
print(f'MAE: {mae:.4f}')
运行与验证
- 安装依赖:
pip install tensorflow opencv-python pandas scikit-learn numpy - 准备数据:将模拟器导出的CSV文件命名为
driving_log.csv,确保其中image_path列为路径,angle列为转向角(弧度)。 - 训练模型:
python train_lane_keeping.py,观察训练损失下降。 - 验证模型:
python evaluate_model.py,记录输出的RMSE和MAE值。
判定标准:若测试集RMSE小于0.1弧度(约5.7度),且训练过程中验证损失持续下降,则判定模型具备车道保持能力。若使用合成数据,仅验证代码流程可运行,不判定模型性能。
数据流与验证观测点
预期输出示例
当使用真实模拟器数据完成训练后,evaluate_model.py的输出格式如下(数值仅为示例,实际结果取决于数据质量与训练轮次):
测试集样本数: 1240
RMSE: 0.0823
MAE: 0.0615
若RMSE小于0.1,说明模型预测转向角与真实转向角平均误差在5.7度以内,可认为模型已学习到车道保持的基本映射关系。若使用合成数据运行,仅验证代码流程无误,不以此数值判定模型性能。