팀세션을 거치며 Reward Function 튜닝에 대한 가닥을 잡아보았다.
이 race의 objective는 ‘가장 빠르게’ ‘off-track’ 없이 track을 완주하는 것이다.
학습에 사용한 첫 reward function이다.
reward_1은 off track을 방지하기 위한 reward이다. 트랙 중심을 기준으로 0.4배의 거리 내에 위치할 경우 높은 보상을 주며 그 범위를 벗어날 경우 현저히 낮은 보상을 받게 된다.
reward_2는 waypoint를 빠르게 따라가는가와 관련된 reward이다. direction uno는 직전의 waypoint와 다음 waypoint의 각돟, direction dos는 다음 waypoint와 다다음 waypoint 의 각도로 두 각의 차이가 작을 경우 직선 구간으로 판단하여 빠른 속도를 지향하도록 설계하였다.
이 두 보상을 각 0.6과 0.4의 가중치를 주어 합한 뒤전체적인 트랙의 구성에서 중앙선의 좌측에 위치하는 것이 유리하므로 중앙선 좌측으로 편향되게 reward를 보정해주었다.
def reward_function(params):
# Read input parameters
track_width = params['track_width']
all_wheels_on_track = params['all_wheels_on_track']
distance_from_center = params['distance_from_center']
waypoints = params['waypoints']
closest_waypoints = params['closest_waypoints']
speed = params['speed']
angle = abs(params['steering_angle'])
heading = params['heading']
isLeft = params['is_left_of_center']
# rewards for each cases
reward_1 = 1
reward_2 = 1
# 5markers that are at varying distances away from the center line
marker_1 = 0.1 * track_width
marker_2 = 0.2 * track_width
marker_25 = 0.25 * track_width
marker_3 = 0.3 * track_width
marker_35 = 0.35 * track_width
marker_4 = 0.4 * track_width
marker_5 = 0.5 * track_width
# dirextion
future_point = waypoints[closest_waypoints[1]+1]
next_point = waypoints[closest_waypoints[1]]
prev_point = waypoints[closest_waypoints[0]]
direction_uno = math.atan2(next_point[1] - prev_point[1], next_point[0] - prev_point[0])
direction_uno = math.degrees(direction_uno)
direction_dos = math.atan2(future_point[1] - next_point[1], future_point[0] - next_point[0])
direction_dos = math.degrees(direction_uno)
# manage off-track
if all_wheels_on_track:
if distance_from_center <= marker_1:
reward_1 = 1.4
elif distance_from_center <= marker_2:
reward_1 = 1.3
elif distance_from_center <= marker_25:
reward_1 = 1.3
elif distance_from_center <= marker_3:
reward_1 = 1.2
elif distance_from_center <= marker_35:
reward_1 = 1.2
elif distance_from_center <= marker_4:
reward_1 = 1.2
elif distance_from_center <= marker_5:
reward_1 = 0.1
else:
reward_1 = 1e-3
else:
reward_1 = 1e-3
dirdiff = abs(direction_uno - direction_dos)
# manage speed
if difdiff < 2:
if 4.0 <speed and speed <= 5.0:
reward_2 = 2.0
elif 3.0 <speed and speed <= 4.0:
reward_2 = 1.8
elif 2.0 <speed and speed <= 3.0:
reward_2 = 1.5
elif 1.0 <speed and speed <= 2.0:
reward_2 = 1.2
elif speed <= 1.0:
reward_2 = 0.3
reward = 0.6*reward_1 + 0.4*reward_2
if not isLeft:
reward *= 0.8
return float(reward)
위 reward function으로 5시간 학습을 진행한 모델의 주행 영상은 아래에서 확인할 수 있다.
Track 3바퀴 도는데 1분 55조 781이 걸려 1448명의 참가자 중 129위의 속도를 확보하였다.
위 결과에서 거리 범위에 대한 코드 오류를 발견하여 아래와 같이 수정한 후 학습을 재진행하였다.
import math
def reward_function(params):
# Example of rewarding the agent to follow center line
# Read input parameters
track_width = params['track_width']
all_wheels_on_track = params['all_wheels_on_track']
distance_from_center = params['distance_from_center']
waypoints = params['waypoints']
closest_waypoints = params['closest_waypoints']
speed = params['speed']
angle = abs(params['steering_angle'])
heading = params['heading']
isLeft = params['is_left_of_center']
reward_1 = 1.0
reward_2 = 1.0
# 5markers that are at varying distances away from the center line
marker_1 = 0.1 * track_width
marker_2 = 0.2 * track_width
marker_25 = 0.25 * track_width
marker_3 = 0.3 * track_width
marker_35 = 0.35 * track_width
marker_4 = 0.4 * track_width
marker_5 = 0.5 * track_width
# dirextion
next_point = waypoints[closest_waypoints[1]]
prev_point = waypoints[closest_waypoints[0]]
if closest_waypoints[1] == len(waypoints)-1:
future_point = waypoints[1]
else:
future_point = waypoints[closest_waypoints[1]+1]
direction_uno = math.atan2(next_point[1] - prev_point[1], next_point[0] - prev_point[0])
direction_uno = math.degrees(direction_uno)
direction_dos = math.atan2(future_point[1] - next_point[1], future_point[0] - next_point[0])
direction_dos = math.degrees(direction_uno)
# manage off-track
if all_wheels_on_track:
if distance_from_center <= marker_1:
reward_1 = 1.2
elif marker_1 < distance_from_center and distance_from_center <= marker_2:
reward_1 = 1.3
elif marker_2 < distance_from_center and distance_from_center <= marker_25:
reward_1 = 1.4
elif marker_25 < distance_from_center and distance_from_center <= marker_3:
reward_1 = 1.4
elif marker_3 < distance_from_center and distance_from_center <= marker_35:
reward_1 = 1.3
elif marker_35 < distance_from_center and distance_from_center <= marker_4:
reward_1 = 1.2
elif marker_4 < distance_from_center and distance_from_center <= marker_5:
reward_1 = 0.1
else:
reward_1 = 1e-3
else:
reward_1 = 1e-3
dirdiff = abs(direction_uno - direction_dos)
# manage speed
if dirdiff < 2:
if 4.0 <speed and speed <= 5.0:
reward_2 = 2.0
elif 3.0 <speed and speed <= 4.0:
reward_2 = 1.8
elif 2.0 <speed and speed <= 3.0:
reward_2 = 1.5
elif 1.0 <speed and speed <= 2.0:
reward_2 = 1.2
elif speed <= 1.0:
reward_2 = 0.3
reward = 0.6*reward_1 + 0.4*reward_2
if not isLeft:
reward *= 0.8
return float(reward)
분명 동일 조건에서 거리 마커에 대한 보상만 수정하였는데 순위는 500위권으로 급락하였다. 무언가 이상함을 느껴 이전 코드로 동이한 학습 시간동안 학습을 시켜보았지만 여전히 순위는 120위권으로 복귀할 수 없는 것을 확인하였다. 동일 방식으로 학습을 시켰는데 이와 같이 차이가 나는 이유는 알 수 없었다.
결과적으로 본 프로젝트는 대회 마감에 따라 최고 순위 129위로 마무리하였다.