A convolutional neural network that learns to steer a car from camera images alone — no lane-detection rules, no hand-tuned logic. It watches a human drive, then drives the simulator itself.
This is end-to-end learning for self-driving: instead of writing code that detects lane lines and computes a steering correction, you show the network thousands of frames of a human driving and let it learn the mapping from pixels straight to steering angle on its own. I built the full pipeline in TensorFlow — data exploration, a balancing and augmentation layer, the NVIDIA PilotNet CNN, and a real-time server that drives the Udacity simulator over a socket connection.
It reproduces the core result from NVIDIA’s 2016 paper “End to End Learning for Self-Driving Cars” on the Udacity simulator dataset, and it’s the class version of a project I’m later extending to real camera-plus-CAN data from my own car.
The trained model driving the simulator autonomously — every steering input is the network’s own prediction from the live camera feed.
During training the network learns from recorded frames. At drive time, drive.py runs a Flask + SocketIO server: the simulator streams live camera frames, the model predicts a steering angle for each one, and a small proportional controller sets the throttle — the exact same preprocessing runs on both sides so the model sees what it was trained on.
The hardest part of behavioral cloning isn’t the network — it’s the data. Most driving is straight, so the raw dataset is dominated by a steering angle of zero. Train on it as-is and the model learns the laziest possible policy: go straight, always. It looks great until the first curve.
A faithful build of NVIDIA’s PilotNet: five convolutional layers extract road features at increasing scales, then four fully-connected layers collapse them into a single steering decision. Because steering is a continuous value, the output neuron is linear — this is regression, not classification — trained on mean-squared-error with the Adam optimizer, ELU activations, batch-norm, and dropout for regularization.
| Layer | Detail | Output | Role |
|---|---|---|---|
| Input | YUV, normalized 0–1 | 66 × 200 × 3 | preprocessed frame |
| Conv 1 | 24 × 5×5, stride 2 | 31 × 98 × 24 | edges, lines |
| Conv 2 | 36 × 5×5, stride 2 | 14 × 47 × 36 | |
| Conv 3 | 48 × 5×5, stride 2 | 5 × 22 × 48 | road shapes |
| Conv 4 | 64 × 3×3, stride 1 | 3 × 20 × 64 | |
| Conv 5 | 64 × 3×3, stride 1 | 1 × 18 × 64 | fine features |
| Flatten + Dropout | 0.5 drop rate | 1152 | regularize |
| Dense 1–4 | 1164 → 100 → 50 → 10, ELU | — | combine features |
| Output | 1 neuron, linear | 1 | steering angle |
Training used early stopping, model checkpointing on validation loss, and learning-rate reduction on plateau — all on an RTX 4060. Validation loss tracked training loss closely the whole way down, so no meaningful overfitting.