TORCS 레이스 AI로 92초를 달성한 팀의 방법 읽기: 106초에 멈춘 나에게 부족했던 것
요약
AI 레이싱 대회에서 자신의 기록과 우수 팀의 기록을 비교 분석하며, 단순히 강화학습만으로는 한계가 있음을 논합니다. 성공적인 AI는 전반적인 제어 규칙 자체를 개선하고, 속도 결정 및 변속 타이밍 등 세부 요소를 분리하여 최적화하는 것이 핵심임을 강조합니다.
핵심 포인트
- 성공은 단순한 강화학습보다 '제어 규칙의 형태' 변경에 달려있다.
- 변속 타이밍, 직선/커브 속도 결정 방식 등을 개별적으로 개선해야 한다.
- AI 성능 향상을 위해 텔레메트리 및 평가 시스템 구축이 필수적이다.

같은 코스를 같은 차로 달리게 하면서, 나의 AI는 106.63초였고, 폴란드 대학 1학년 팀의 AI는 92.04초였습니다. 게다가 그들 역시 도중에 나와 같은 106~107초에서 멈춘 적이 있었습니다.
저는 2026년 봄에 영국 대학으로 교환학생을 갔을 때, IBM AI Racing League라는 대회에서 TORCS 레이스 AI를 만들었습니다. 제가 있던 영국 디스코드에서는 당시 '100초대가 가장 빠른 구간'이라고 했고, 106초대는 그 안에 속했습니다. 제출 후에 다른 나라 회차에서 92.04초를 기록한 팀(Overclocked)이 개발 기록과 리포트를 공개하는 것을 발견했습니다.
이 글에서는 그 리포트를 일본어로 읽고, 제 코드와 비교하며 저에게 무엇이 부족했는지 생각합니다. 속도 결정 방식, 변속 타이밍, 주행 라인 3점을 중심으로 비교할 것입니다.
다만, 제 기록은 2주차 이후의 최고랩(best lap)이고, 그들의 기록은 정지 상태에서의 1회전입니다. 연료와 데미지 조건도 다릅니다. 92.04초는 그들이 공표한 값이며, 제가 같은 환경에서 재현한 값이 아닙니다.
이 글을 통해 알 수 있는 것은 다음 네 가지입니다.
- 92초 팀이 어떻게 106~107초의 벽을 넘었는지
- 제로(Zero)에서의 강화학습 (SAC)이 그들의 환경에서는 105초대까지 진전되었지만, 제 환경에서는 한 바퀴도 돌지 못한 이유
- 저의 속도 규칙이 직선 구간에서 194km/h에 머물렀던 것
- 다음에 같은 문제에 도전한다면 무엇부터 바꿔야 하는가
결론
- 92초 팀의 주역은 강화학습이 아니라, 손으로 만든 제어 규칙(약 50개의 상수)과 그 상수를 약 15,000회의 시도로 조정한 탐색이었습니다. 강화학습은 그것을 신경망에 옮긴 후 보정하는 데 사용되었습니다.
- 106
107초에서 나온 약 18초는 변속 타이밍에서 약 4초, 직선과 커브의 속도 결정 방식을 나누어 약 10초, 주행 라인에서 23초였습니다. 이 모든 것은 '탐색의 양'이 아니라 '제어 규칙의 형태'를 바꾼 것에 의한 개선입니다. - 저의 규칙은 전방 거리에 비례하여 속도를 결정하고 상한을 194.3km/h로 설정했습니다. 직선과 커브가 하나의 계수로 연결되어, 그들이 107초에서 멈췄던 형태와 같습니다.
- 저에게 부족했던 것은 한 바퀴 동안의 속도를 세밀하게 기록으로 확인하는 것(텔레메트리)과 평가 횟수를 늘리는 시스템이었습니다.
전제: 무엇을 비교하고 있는가
비교하기 전에, 조건의 차이를 정리해 두겠습니다.
| 나 (Team 06) | Overclocked | |
|---|---|---|
| 대학 | 영국 대학 | Politechnika Świętokrzyska (폴란드) |
| ... | ||
| 시작부터의 1회전은, 멈춘 상태에서 가속하는 만큼만, 2주차 이후보다 불리합니다. 연료와 데미지가 있는 조건도 불리하게 작용합니다. 그럼에도 불구하고 14초 이상의 차이가 납니다. |
아래 내용은 그들의 사이트와 6페이지의 리포트에 쓰여진 내용입니다. 코드는 공개되어 있지 않으며, 멤버의 GitHub에서도 TORCS 코드는 보이지 않습니다. 92.04초 역시 자신들이 제출한 스크립트로 측정한 값이며, 운영사 공식 순위표는 찾을 수 없었습니다. 따라서 수치는 검증할 수 없지만, 리포트 설명은 물리적으로 논리적이고, 규칙(차의 물리 모델은 변경하지 않고 AI 코드만 변경)에 위배되는 서술도 없습니다.
그들의 흐름: 강화학습에서 손으로 만든 제어 규칙으로
리포트에 따르면 개발 과정은 5단계였습니다.
- 제로(Zero)에서의 SAC: 네트워크 크기를 3가지로 시도했지만, 어느 것도 비슷한 주행 성능을 보여주지 못했습니다. -
- 환경 재구축: 기어를 회전수로 자동 전환하고, 조작을 핸들과 액셀 두 가지로 줄이며, 보상을 다시 만들었습니다. 이로 105~115초가 나왔습니다. -
- 학습 안정화: 긴 학습으로 가치 추정이 발산한 원인을 조사하여 수정했습니다. -
- 손 위 강화학습 쌓기: 손으로 배운 107초 주행 위에, 보정(correction)을 SAC로 배워 약 103초가 되었습니다. -
- 손으로 만든 제어 규칙 탐색 후 조정하고 네트워크에 옮기기: 88.8초의 제어 규칙을 만들고, 비헤이비어 클로닝 (Behavior Cloning)과 DAgger를 이용해 네트워크에 옮겨 92.04초가 되었습니다.
단계 4에서 약 103초가 된 후, '학습량을 늘리면 106초의 벽을 넘을 수 있다'는 생각은 틀렸다고 리포트는 적고 있습니다. 그래서 역할을 역전시켰습니다. 속도는 손으로 만든 제어 규칙에 맡기고, 학습은 '제출물을 신경망으로 만드는 압축'에 사용하는 방침입니다.
제가 강화학습을 포기하고 단순한 규칙의 상수를 CMA-ES로 탐색하는 방법으로 전환한 것과 발상은 같습니다. 달랐던 것은 그 이후였습니다.
그들의 제어 규칙별 기록 시간입니다 (리포트 값). 전방 거리에 따라 속도를 결정하는 v2가 105.8초였고, 이곳은 저의 규칙과 거의 같은 형태와 비슷한 시간이었습니다. 거기서부터 v5로 한 번에 91.2초까지 단축되었습니다.
차이점 1: 변속 타이밍
속도와 주행 거리를 1바퀴 기준으로 기록해 보니, 어느 직선 구간에서도 174km/h에서 최고 속도가 나고 있었습니다. 엔진은 18,700회전까지 돌 수 있는데도, 그때까지의 제어 규칙과 강화학습(RL) 모두 약 8,200회전에서 시프트 업하고 있었습니다. 시프트 업을 17,800회전으로 올리자 최고 속도가 184km/h가 되었고, 즉시 약 4초 단축되었습니다.
랩 타임만 보고는 이 최고 속도 제한이 보이지 않습니다. 그들은 '속도를 거리별로 그려보니 알 수 있었다'고 적었습니다.
제 차는 기어 변속을 gym_torcs 측의 규칙(속도에 따라 변속하는, 제공된 샘플 규칙)에 맡기고 회전수는 한 번도 기록하지 않았습니다. 같은 최고 속도 제한이 있었는지 여부는 이제 와서는 알 수 없습니다.
차이점 2: 직선과 커브의 속도를 분리
두 번째는 속도를 결정하는 방식입니다. 그들의 v4는 '커브에서 나올 수 있는 속도는 반지름의 제곱근에 비례한다'라는 물리적 요소를 넣은 형태였지만, 하나의 계수가 '커브 속도'와 '직선 속도' 둘 다를 결정하고 있었습니다. 커브에서 안전한 값으로 설정하면 직선이 느려지고, 직선에서 빠른 값으로 설정하면 커브에서 튀어나갑니다. 탐색을 해봐도 107초에서 멈췄습니다.
v5에서는 이를 두 개로 나누었습니다. 전방의 가장 짧은 거리 센서에서 커브 정점에서의 속도를 결정하고, 가장 긴 거리 센서에서 '어디까지 브레이크를 늦출 수 있는지'를 더합니다. 직선은 차의 한계까지 내고, 커브만 낮추는 형태입니다. 최고 속도는 244.5km/h가 되었고, 1바퀴는 약 101초에서 91.2초로 줄었습니다.
저의 규칙을 같은 눈으로 다시 살펴보겠습니다.
![제 규칙의 목표 속도. 가로축은 정면 코스 끝까지의 거리(track[9]), 세로축은 목표 속도. 거리에 비례하여 올라가서 약 89m에서 상한 C=194.3km/h에 도달하고, 그 이상은 평평해진다. 위에는 Overclocked 차량이 급커브 전 직선에서 내던 약 248km/h의 점선](https://static.zenn.studio/user-upload/deployed-images/ebb7f7da81d46be3b0866806.png?sha=a93070510aca7e824535e5e5229be1fce8a5e9d3)
저의 규칙은 v_target = clip(K × track[9], 30, C)로, 최종 값은 K = 2.171, C = 194.3km/h였습니다. 전방이 약 89m 이상 열려 있으면 목표 속도는 그 이상 아무리 직선이 계속되어도 194km/h입니다. 골인 직전의 직선만 액셀을 끝까지 밟았기 때문에 238km/h까지 나왔지만, 그 외의 직선은 모두 194km/h에서 최고 속도가 나고 있었습니다.
C를 CMA-ES가 194km/h에 수렴시킨 것은 아마도 우연이 아닐 것입니다. K와 C가 하나의 규칙 안에서 연결되어 있기 때문에, C를 올리면 직선 끝의 커브로 너무 빠른 속도로 진입하게 됩니다. 저는 이것을 최종 코너 직전만 계수를 바꾸거나, 급커브 구간에만 상한을 두거나, 골인 직전만 전개하는 '구간별 덧대기'로 해결하려고 했습니다. 그들은 규칙의 형태 자체를 바꿨습니다.
리포트에는 '아무리 하이퍼파라미터를 찾아도 모델 구조로 표현할 수 없는 것은 되찾을 수 없다'고 있습니다. 저 역시 불감대를 넣었을 때 같은 경험을 했지만, 속도의 규칙 형태는 끝까지 의심하지 않았습니다.
차이점 3: 시도한 횟수
세 번째는 평가 횟수입니다. 그들은 TORCS를 화면 없이 빌드하여 하나의 PC로 최대 10개를 동시에 구동하고, 최대 4대의 PC로 탐색을 진행했습니다. 총 시도는 약 15,000회입니다.
저는 화면이 있는 TORCS로 하나씩 구동했기 때문에, 한 번의 평가가 4바퀴였고, 8시간 최적화에서도 평가는 수십 회에 불과했습니다. 약 100배의 차이가 있습니다. 환경을 처음에 컨테이너로 고정했다면, 화면 없이 병렬로 돌릴 방법도 있었습니다.
강화학습이 그들의 환경에서 105초대까지 진전된 이유
저 역시 SAC를 약 1,000번은 시도했지만, 한 바퀴도 돌지 못했습니다. 그들의 제로(zero)에서의 SAC는 105~115초까지 진행되었습니다. 차이점을 나열해 보면, 학습 방법보다 환경을 만드는 방식에서 차이가 있었습니다.
내 SAC | 그들의 SAC |
|---|---|---|
| 기어 | gear_change=False로 1단에 고정 | 회전수에 따라 자동 변경 |
| 보상 | 코스 중앙에 있으면, 멈춰 있어도 점수 획득 | 전진 거리, 시간 비용, 1회전 보너스 |
| 중단 조건 | 느리면 약 10초 후 중단 | 코스 외부에 0.6초 이상 나가면 중단 (연석 사용 가능) |
| 학습량 | 총 시도 횟수 약 1,000회 | 한 번의 학습으로 약 80만 스텝 |
1단을 고정하면 아무리 학습해도 빠르게 달릴 수 없습니다. 멈춰 있어도 점수를 얻는 보상에서는 달리느니 멈추는 것이 더 이득입니다. 나의 SAC는 학습이 시작되기 전 단계에서 막혔습니다.
그들의 보고서에는 모방으로 학습시킨 주행을 강화학습(RL)이 무너뜨리는 실패나, 네트워크가 '지난번과 같은 핸들 각도를 출력하는' 것만 기억해버리는 실패가 원인과 함께 기록되어 있습니다. 이는 내가 SAC에서 본 '모방 직후는 좋은데, 학습이 진행되면 무너지는' 현상과 같은 종류입니다. 그들은 이를 기록하고 하나씩 수정했지만, 나는 고치지 않고 방법을 바꿨습니다.
나에게 부족했던 것
보고서 마지막에 그들은 '큰 진전 앞에는 반드시 측정이 있었다', '추측이 측정보다 먼저 나온 때는 두 번 모두 헛발질이었다'고 적었습니다. 나에게 부족했던 것이 바로 이것이었습니다.
1회전 전체를 측정하고 있지 않았습니다. 내가 본 것은 랩타임과 충돌 지점의 주행 거리뿐이었습니다. 구간별 속도, 회전수, 기어를 기록했다면, 직선 구간이 시속 194km로 평평해진 것은 그래프 한 장으로 보였을 것입니다. -
규칙의 형태를 의심하지 않았습니다. 상수는 탐색했지만, 규칙의 형태는 처음에 정한 대로 두고 구간별 이어 붙이기(継ぎはぎ)로 대응했습니다. -
평가 횟수를 늘리는 장치가 없었습니다. 화면으로 보면서 한 번씩 주행했기 때문에, 8시간 동안 수십 회가 한계였습니다. -
혼자였습니다. 그들의 사이트에는 6명이 올라와 있었고, 리더를 겸하는 사람을 포함해 신경망 담당이 3명, 사이트 담당이 2명, SNS 담당이 1명으로 역할을 분담했습니다. 나는 개발을 거의 혼자 진행하고 있었습니다. -
시간 활용 방식도 달랐습니다. 그들의 개발 기록은 3월 하순부터 6월 말까지 이어졌고, 큰 개선은 6월에 집중되었습니다. 나의 제출은 5월이었고, 실제로 개선을 시도한 것은 약 2주였습니다.
개발 효율의 차이에는 도구의 차이도 있었을지 모릅니다. IBM의 AI 코딩 에이전트인 IBM Bob의 일반 제공이 시작된 것이 4월 28일이었고, 그들의 큰 개선은 그 이후입니다. 다만, 보고서에 나온 AI 도구는 주행 기록 분석에 사용한 IBM Granite뿐이며, Bob을 사용했는지 여부는 쓰여 있지 않습니다.
다음에 같은 문제에 도전한다면
순서를 매기자면 다음과 같습니다.
먼저, 1회전 전체의 속도/회전수/기어/횡 위치를 기록하는 장치를 만듭니다. 랩타임보다 먼저, 1회전 그래프를 봅니다. -
환경을 컨테이너로 고정하고, 화면 없이 병렬로 실행합니다. 평가 횟수를 초기에 확보합니다. -
속도의 규칙은 물리적으로 구성합니다. 커브의 속도는 반경으로부터, 직선의 속도는 브레이크가 감당할 수 있는 거리로부터 정하며, 하나의 계수로 연결할 수 없습니다. -
상수의 탐색은 그 후에 합니다. 형태가 결정된 후에 탐색하는 것이 시도를 낭비하지 않습니다.
2번 환경 고정은 제출 후에 공개 버전을 다시 만들 때 나중에 했습니다. 처음부터 이 순서로 했다면, 106초에 멈추지 않았을지도 모릅니다.
나의 코드는 sean-from-japan/torcs-racing-controller에서 공개하고 있습니다. Overclocked 기록은 overclocked.run에서 볼 수 있습니다.
토론

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn ML의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기