
Dự án này làm gì
self-driving-car là một mô phỏng lái xe tự hành nhỏ gọn, được viết hoàn toàn bằng JavaScript thuần. Một mạng nơ-ron nhỏ học qua quá trình tiến hóa để chạy trên đường cao tốc cong ba làn, giữ làn, phanh khi gặp xe cộ, bật xi-nhan, vượt các xe chậm hơn và trở lại làn bên phải khi phù hợp.
Không có tài xế mẫu nào chỉ ra hành vi đúng. Thay vào đó, mỗi thế hệ đưa một quần thể mạng nơ-ron lên cùng một con đường. Những mạng đi được xa nhất sẽ nhận điểm thích nghi cao hơn và trở thành thế hệ cha mẹ của thế hệ tiếp theo.
Dự án gồm khoảng 1.300 dòng mã ES module, bao quát đường, vật lý xe, nhận thức, giao thông, mạng nơ-ron, thuật toán di truyền, bộ lập kế hoạch, kết xuất và giao diện người dùng. Dự án không có dependency thời gian chạy, và các module mô phỏng giống nhau có thể chạy trên cả trình duyệt lẫn Node.js.
Bạn có thể mở bản demo trực tiếp để xem tài xế đã được huấn luyện trước, tiến hóa một quần thể ngay trên trình duyệt hoặc tự điều khiển xe.
Hệ thống lái xe hoạt động như thế nào
Mô phỏng tiến triển ở tốc độ cố định 60 bước mỗi giây. Ở mỗi bước, xe quét các làn lân cận, chuyển các quan sát thành 19 đầu vào cho mạng nơ-ron và tạo ra hai đầu ra: lệnh bàn đạp ga/phanh và làn được yêu cầu.
Nhận thức và mạng nơ-ron
Mạng không xử lý điểm ảnh camera hay các tia khoảng cách thô. Nó nhận thông tin có cấu trúc tương tự dữ liệu mà một hệ thống nhận thức có thể cung cấp cho bộ lập kế hoạch lái xe:
- Làn bên trái, làn hiện tại và làn bên phải có tồn tại hay không.
- Xe gần nhất phía trước và phía sau trong mỗi làn liên quan.
- Tốc độ thu hẹp của từng khoảng cách.
- Tốc độ hiện tại của xe đang học.
- Độ cong gắt nhất trong 100 mét tiếp theo.
- Trạng thái hiện tại của bộ lập kế hoạch chuyển làn.
Kiến trúc là 19 · 12 · 8 · 2, sử dụng hàm kích hoạt tanh và chứa 362 trọng số. Một đầu ra điều khiển bàn đạp. Đầu ra còn lại chọn làn: giá trị lớn hơn +0.5 yêu cầu chuyển sang làn bên trái, còn giá trị nhỏ hơn -0.5 yêu cầu chuyển sang làn bên phải.
Bộ lập kế hoạch và mô hình xe
Mạng nơ-ron quyết định khi nào và ở đâu cần di chuyển, nhưng không trực tiếp đánh lái. Bộ lập kế hoạch được viết thủ công chuyển yêu cầu đổi làn thành một thao tác an toàn, mượt mà. Xe bật xi-nhan trong 0.7 giây, kiểm tra làn mục tiêu, đi theo đường cong S bậc năm trong 2.6 giây và sử dụng điều khiển bám đuổi thuần túy để bám theo lộ trình đã lập.
Nếu một xe khác chạy ngang hàng với xe hoặc sắp đi vào điểm mù, bộ lập kế hoạch tiếp tục bật xi-nhan và chờ khoảng trống mở ra. Việc nhả yêu cầu trong giai đoạn báo hiệu sẽ hủy thao tác.
Bản thân xe sử dụng mô hình xe đạp động học với các đơn vị SI. Các tham số tương tự một mẫu hatchback gia đình: dài 4.4 mét, tăng tốc từ 0 lên 100 km/h trong 9.8 giây, tốc độ tối đa 115 km/h và lực phanh lên tới 8 m/s². Độ bám đường khi vào cua giới hạn tốc độ xe có thể vượt qua khúc cua.
Giao thông, điểm thích nghi và tiến hóa
Giao thông nền tuân theo Mô hình Tài xế Thông minh. Các xe có tốc độ mong muốn từ 61 đến 94 km/h, vượt bên trái, trở lại bên phải sau khi vượt, bật xi-nhan trước khi chuyển làn và phản ứng với xe đang học.
Điểm thích nghi chủ yếu là số mét đã di chuyển. Xe mất 300 điểm nếu đâm hoặc bị một hàng xe chậm đang quét dọc con đường bắt kịp. Xe cũng mất bốn mét cho mỗi giây chạy trong làn bên trái khi làn bên phải rõ ràng đang trống. Không có phần thưởng trực tiếp cho việc vượt; vượt trở nên hữu ích vì giúp xe đi được quãng đường dài hơn.
Quá trình tiến hóa sử dụng bốn kỹ thuật chính:
- Giữ cá thể ưu tú: bốn mạng tốt nhất được giữ nguyên trong quá trình huấn luyện qua dòng lệnh.
- Chọn đấu giải: các mạng mạnh hơn có khả năng được chọn làm cha mẹ cao hơn.
- Lai BLX-0.25: các trọng số của cha mẹ được pha trộn để tạo ra thế hệ con.
- Đột biến Gaussian: tỷ lệ và biên độ đột biến giảm dần với chu kỳ bán rã 40 thế hệ.
Cài đặt và thiết lập cục bộ
Sao chép kho mã và khởi động máy chủ tĩnh cục bộ:
git clone https://github.com/Stxqq/self-driving-car.git
cd self-driving-car
npm run serve
Lệnh serve khởi động máy chủ HTTP Python trên cổng 5101. Mở http://localhost:5101 trong trình duyệt.
Không cần cài đặt package nào. Bất kỳ máy chủ web tĩnh nào cũng có thể lưu trữ dự án, nhưng mở trực tiếp trang qua file:// sẽ không hoạt động vì trình duyệt hạn chế ES module trong ngữ cảnh đó.
Cần Node.js 22 trở lên để chạy các tập lệnh kiểm thử và dòng lệnh. Chạy bộ kiểm thử bằng:
npm test
Sử dụng giao diện trình duyệt
Xem tài xế đã được huấn luyện trước
Sử dụng chế độ xem để quan sát mạng đã cung cấp điều khiển xe qua dòng giao thông. Trang hiển thị các đầu vào, đầu ra, lộ trình đã lập, trạng thái chuyển làn và số liệu xe. Dải băng màu xanh biểu thị lộ trình do bộ lập kế hoạch tạo ra.
Tự lái xe
Ở chế độ Drive, bạn thay thế mạng nơ-ron nhưng vẫn giữ nguyên bộ lập kế hoạch. Xe bắt đầu với hệ thống ga tự động được đặt ở 70 km/h.
- Giữ
↑để tăng tốc độ cài đặt. - Nhấn
↓để phanh và giảm tốc độ cài đặt. - Nhấn
←để yêu cầu chuyển sang làn bên trái. - Nhấn
→để yêu cầu chuyển sang làn bên phải.
Thẻ mạng vẫn tiếp tục hiển thị hành động mà bộ não đã được huấn luyện trước sẽ thực hiện, giúp chế độ này hữu ích khi so sánh quyết định của bạn với quyết định của nó.
Huấn luyện trên trình duyệt
Chế độ huấn luyện bắt đầu với 60 xe có trọng số mạng ngẫu nhiên. Tất cả xe dùng chung một con đường trong mỗi thế hệ, và giao thông tăng dần trong 15 thế hệ đầu tiên. Các vòng đầu kéo dài 45 giây. Khi một xe sống sót đến cuối vòng, thời lượng các vòng sau tăng thêm một nửa cho đến khi đạt tối đa 5 phút.
Huấn luyện trên trình duyệt nhanh chóng phát hiện hành vi giữ làn và bám theo, nhưng vượt xe khó hơn nhiều. Các thử nghiệm được mô tả trong dự án cho thấy các quần thể khởi tạo ngẫu nhiên thường chỉ thực hiện 0,1 đến 0,5 lần chuyển làn mỗi kilômét cho đến thế hệ 15. Trình điều khiển được huấn luyện trước ban đầu cần khoảng 170 thế hệ với quần thể 200 xe trước khi chuyển làn mang lại lợi ích.
Chọn Từ mô hình đã huấn luyện khi bạn muốn tiến hóa các đột biến nhẹ từ bộ não được cung cấp, thay vì bắt đầu với trọng số ngẫu nhiên. Các bộ não được huấn luyện trên trang có thể xuất dưới dạng JSON và tải lại sau bằng nút Nhập.
Huấn luyện từ Dòng lệnh
Huấn luyện từ dòng lệnh chạy ở chế độ không giao diện trên nhiều luồng worker. Ví dụ sau huấn luyện một quần thể gồm 120 mạng trong 10 thế hệ, đánh giá mỗi mạng trên ba con đường có seed với các lượt chạy dài 60 giây:
node scripts/train.mjs --generations 10 --population 120 --seeds 3 --seconds 60
Mặc định, bộ não tạo ra được ghi vào runs/brain.json. Điều này giúp tách các thử nghiệm khỏi mạng được cung cấp trong src/brains/pretrained.json.
Bộ huấn luyện báo cáo các thống kê như quãng đường tốt nhất và trung bình, số xe sống sót, tỷ lệ đột biến và thời gian đã trôi qua. Thế hệ 0 có thể đã chứa những xe sống sót qua toàn bộ một lượt chạy ngắn vì bộ lập kế hoạch giữ chúng ở giữa làn. Do đó, tiến bộ thường dễ nhận thấy hơn qua mức trung bình của quần thể đang tăng lên thay vì qua một kết quả tốt nhất duy nhất.
Tùy chọn Huấn luyện Hữu ích
--densitythay đổi mật độ giao thông.--resumebắt đầu từ bộ não tại đường dẫn được chỉ định bởi--outvà sử dụng đột biến nhẹ hơn.--generationskiểm soát số vòng tiến hóa.--populationkiểm soát số bộ não được đánh giá trong mỗi thế hệ.--seedskiểm soát số seed của con đường được sử dụng.--secondsđặt thời lượng của mỗi lượt chạy.
Quy trình huấn luyện được sử dụng cho bộ não được cung cấp được ghi lại trong scripts/curriculum.sh. Quy trình bắt đầu từ các lượt chạy dài 2 phút trong điều kiện giao thông đầy đủ, sau đó tăng lên các lượt chạy dài 5 phút trên nhiều con đường hơn, rồi kết thúc bằng giai đoạn tinh chỉnh giữ bên phải. Theo tài liệu dự án, chương trình này mất khoảng 1 giờ trên máy tính xách tay 14 lõi.
Đánh giá Bộ não đã Huấn luyện
Việc đánh giá đo lường hiệu quả của một bộ não trên các con đường xác định mà nó chưa từng gặp trong quá trình huấn luyện. Chạy bộ đánh giá với danh sách seed của các con đường:
node scripts/evaluate.mjs --seeds 9001,9002,9003,9004,9005
Kết quả hiển thị quãng đường, thời gian đã trôi qua, tốc độ trung bình, số lần chuyển làn và liệu mỗi lượt chạy kết thúc do hết thời gian hay xe va chạm. Kết quả cũng tính các giá trị tổng hợp như quãng đường trung bình và trung vị.
Để đánh giá một mạng đã xuất hoặc mới huấn luyện thay vì bộ não được cung cấp, truyền tệp JSON của mạng đó bằng --brain:
node scripts/evaluate.mjs --brain runs/brain.json --seeds 9001,9002,9003
Có thể tạo lại kết quả chính thức bằng:
npm run evaluate -- --write
Lệnh này ghi scripts/results.json, tệp cũng được giao diện trình duyệt đọc.
Tìm hiểu Kết quả đã Công bố
Mạng 362 trọng số được cung cấp đã được kiểm tra trong 5 phút trên 30 seed giữ lại, trong điều kiện giao thông đầy đủ. Mạng đạt quãng đường trung bình 6,90 km, trung vị 7,23 km và tốc độ trung bình 87 km/h. Hai mươi tám trong số 30 lượt chạy vẫn đang hoạt động sau 5 phút, và xe thực hiện trung bình 5,1 lần chuyển làn mỗi kilômét.
Dự án so sánh hệ thống này với một phiên bản cũ hơn, vốn điều khiển trực tiếp dựa trên 14 cảm biến tia. Mạng cũ đạt trung bình 4,05 km và 56 km/h, với 20 trong số 30 lượt chạy vẫn hoạt động sau 5 phút. Đây không phải là một phép đo chuẩn có kiểm soát vì mô hình giao thông cũng đã thay đổi, nhưng nó cho thấy vì sao việc tách quyết định học được khỏi thao tác lái do bộ lập kế hoạch thực hiện giúp phát hiện hành vi vượt xe dễ hơn.
Mạng chọn bàn đạp và làn mục tiêu; bộ lập kế hoạch xử lý việc bật tín hiệu, kiểm tra khoảng trống và đánh lái mượt.
Mẹo Nâng cao
Sử dụng Nhiều Seed để Giảm Quá khớp
Một bộ não hoạt động tốt trên một con đường có thể thất bại trên con đường khác. Hãy tăng số seed huấn luyện và dành các seed riêng cho việc xác thực và đánh giá cuối cùng. Bộ huấn luyện không giao diện đánh giá từng bộ não riêng trên con đường của nó vì giao thông phản ứng với xe đang học; điều này ngăn hành vi của một ứng viên làm thay đổi điểm số của ứng viên khác.
Tiếp tục trước khi Bắt đầu lại
Nếu một bộ não đã huấn luyện có thể giữ làn và tránh giao thông, hãy sử dụng --resume hoặc tùy chọn mô hình được huấn luyện trước trên trình duyệt. Bắt đầu từ trọng số ngẫu nhiên phù hợp để quan sát quá trình tiến hóa từ đầu, nhưng hành vi vượt xe phức tạp có thể cần nhiều thế hệ hơn và quần thể lớn hơn.
Tăng Dần Độ khó
Hãy tuân theo cách tiếp cận chương trình huấn luyện của kho lưu trữ: bắt đầu với độ dài lượt chạy vừa phải, sau đó tăng thời lượng, sự đa dạng của con đường và độ sâu đánh giá. Các lượt chạy dài hơn cung cấp bằng chứng tốt hơn về khả năng lái ổn định, nhưng khiến mỗi thế hệ tốn nhiều tài nguyên hơn.
Giữ Tính Xác định
Mô phỏng có tính xác định đến từng bước thời gian cố định: các seed và bộ não giống nhau tạo ra các quỹ đạo giống nhau. Các tùy chọn tốc độ chạy nhiều bước mô phỏng 1/60 giây hơn trong mỗi khung hình được kết xuất, thay vì thay đổi bước vật lý. Điều này cho phép huấn luyện tăng tốc mà không làm thay đổi kết quả.
Biết Nơi Chỉnh sửa Dự án
src/sim/chứa mã nguồn về đường, xe, nhận thức, bộ lập kế hoạch, giao thông, thế giới, bộ não và tiến hóa mà không phụ thuộc vào DOM.src/render/chứa sân khấu canvas, phần trực quan hóa mạng, giao diện giải phẫu và biểu đồ.src/ui/chứa các phiên theo dõi, huấn luyện và lái xe, bộ nhớ lưu trữ cùng cơ chế xử lý bàn phím.src/brains/chứa mạng đã được huấn luyện trước.scripts/chứa các tệp huấn luyện, chương trình học, đánh giá và kết quả.test/chứa các bài kiểm thử Node.js, bao gồm cả kiểm tra phát lại trên dữ liệu chưa được dùng trong huấn luyện.
Kết luận
Dự án này cho thấy một mạng nơ-ron rất nhỏ có thể học các quyết định lái xe ở cấp độ cao như thế nào khi một bộ lập kế hoạch thông thường đảm nhiệm việc điều khiển lái chính xác và thực hiện chuyển làn. Hãy bắt đầu bằng cách chạy bản demo trên trình duyệt, so sánh các quyết định thủ công và quyết định của mạng nơ-ron, sau đó sử dụng các tập lệnh Node.js để huấn luyện và đánh giá các bộ não của riêng bạn. Cách triển khai không phụ thuộc thư viện và mô phỏng mang tính xác định cũng khiến đây trở thành một codebase thực tế để nghiên cứu việc học tiến hóa, mô hình xe, hành vi giao thông và lập kế hoạch.
