Reinforcement Learning in AirSim#
Wir beschreiben im Folgenden, wie wir DQN in AirSim mithilfe eines OpenAI Gym Wrappers um die AirSim API und mithilfe von Stable Baselines Implementierungen von Standard-RL-Algorithmen implementieren können. Wir empfehlen die Installation von stable-baselines3, um diese Beispiele auszuführen (siehe https://github.com/DLR-RM/stable-baselines3).
Haftungsausschluss#
Dies befindet sich noch in aktiver Entwicklung. Was wir unten teilen, ist ein Framework, das erweitert und angepasst werden kann, um eine bessere Leistung zu erzielen.
Gym Wrapper#
Um AirSim als Gym-Umgebung nutzen zu können, erweitern und implementieren wir die Basis-Methoden wie step, _get_obs, _compute_reward und reset neu, die spezifisch für AirSim und die jeweilige Aufgabe sind. Die Beispielumgebungen, die in diesen Beispielen für Auto und Drohne verwendet werden, finden Sie unter PythonClient/reinforcement_learning/*_env.py.
RL mit Auto#
Dieses Beispiel funktioniert mit der AirSimNeighborhood-Umgebung, die in Releases verfügbar ist.
Zuerst müssen wir die Bilder aus der Simulation abrufen und sie entsprechend transformieren. Unten zeigen wir, wie ein Tiefenbild von der Ego-Kamera erhalten und in eine 84x84-Eingabe für das Netzwerk transformiert werden kann. (Sie können auch andere Sensormodalitäten und Sensoreingänge verwenden – natürlich müssen Sie den Code entsprechend anpassen).
responses = client.simGetImages([ImageRequest(0, AirSimImageType.DepthPerspective, True, False)])
current_state = transform_input(responses)
Wir definieren weiter die sechs Aktionen (bremsen, geradeaus mit Gas, voll links mit Gas, voll rechts mit Gas, halb links mit Gas, halb rechts mit Gas), die ein Agent ausführen kann. Dies geschieht über die Funktion interpret_action.
def interpret_action(action):
car_controls.brake = 0
car_controls.throttle = 1
if action == 0:
car_controls.throttle = 0
car_controls.brake = 1
elif action == 1:
car_controls.steering = 0
elif action == 2:
car_controls.steering = 0.5
elif action == 3:
car_controls.steering = -0.5
elif action == 4:
car_controls.steering = 0.25
else:
car_controls.steering = -0.25
return car_controls
Wir definieren dann die Belohnungsfunktion in _compute_reward als eine konvexe Kombination aus der Geschwindigkeit des Fahrzeugs und seiner Abweichung von der Mittellinie. Der Agent erhält eine hohe Belohnung, wenn er sich schnell bewegt und in der Mitte der Fahrspur bleibt.
def _compute_reward(car_state):
MAX_SPEED = 300
MIN_SPEED = 10
thresh_dist = 3.5
beta = 3
z = 0
pts = [np.array([0, -1, z]), np.array([130, -1, z]), np.array([130, 125, z]), np.array([0, 125, z]), np.array([0, -1, z]), np.array([130, -1, z]), np.array([130, -128, z]), np.array([0, -128, z]), np.array([0, -1, z])]
pd = car_state.position
car_pt = np.array(list(pd.values()))
dist = 10000000
for i in range(0, len(pts)-1):
dist = min(dist, np.linalg.norm(np.cross((car_pt - pts[i]), (car_pt - pts[i+1])))/np.linalg.norm(pts[i]-pts[i+1]))
#print(dist)
if dist > thresh_dist:
reward = -3
else:
reward_dist = (math.exp(-beta*dist) - 0.5)
reward_speed = (((car_state.speed - MIN_SPEED)/(MAX_SPEED - MIN_SPEED)) - 0.5)
reward = reward_dist + reward_speed
return reward
Die Funktion zur Berechnung der Belohnung bestimmt anschließend, ob die Episode beendet ist (z.B. aufgrund einer Kollision). Wir betrachten die Geschwindigkeit des Fahrzeugs und wenn diese unter einem Schwellenwert liegt, wird die Episode als beendet betrachtet.
done = 0
if reward < -1:
done = 1
if car_controls.brake == 0:
if car_state.speed <= 5:
done = 1
return done
Die Hauptschleife sequenziert dann das Abrufen des Bildes, die Berechnung der zu ergreifenden Aktion gemäß der aktuellen Strategie, das Erhalten einer Belohnung und so weiter. Wenn die Episode beendet ist, setzen wir das Fahrzeug über reset() in den ursprünglichen Zustand zurück.
client.reset()
client.enableApiControl(True)
client.armDisarm(True)
car_control = interpret_action(1) // Reset position and drive straight for one second
client.setCarControls(car_control)
time.sleep(1)
Sobald der Gym-ähnliche Umgebungs-Wrapper wie in car_env.py definiert ist, verwenden wir Stable Baselines 3, um eine DQN-Trainingsschleife auszuführen. Das DQN-Training kann wie folgt konfiguriert werden, wie in dqn_car.py zu sehen ist.
model = DQN(
"CnnPolicy",
env,
learning_rate=0.00025,
verbose=1,
batch_size=32,
train_freq=4,
target_update_interval=10000,
learning_starts=200000,
buffer_size=500000,
max_grad_norm=10,
exploration_fraction=0.1,
exploration_final_eps=0.01,
device="cuda",
tensorboard_log="./tb_logs/",
)
Eine Trainingsumgebung und eine Evaluierungsumgebung (siehe EvalCallback in dqn_car.py) können definiert werden. Die Evaluierungsumgebung kann sich von der Trainingsumgebung unterscheiden und andere Abbruchbedingungen/Szenenkonfigurationen aufweisen. Ein Tensorboard-Logverzeichnis wird ebenfalls als Teil der DQN-Parameter definiert. Schließlich startet model.learn() die DQN-Trainingsschleife. Ähnlich können Implementierungen von PPO, A3C usw. aus Stable Baselines 3 verwendet werden.
Beachten Sie, dass die Simulation hochgefahren und ausgeführt sein muss, bevor Sie dqn_car.py ausführen. Das folgende Video zeigt die ersten paar Episoden des DQN-Trainings.
RL mit Quadrocopter#
Dieses Beispiel funktioniert mit der AirSimMountainLandscape-Umgebung, die in Releases verfügbar ist.
Wir können RL ähnlich für verschiedene autonome Flug-Szenarien mit Quadrocoptern anwenden. Unten ist ein Beispiel dafür, wie RL verwendet werden könnte, um Quadrocopter darauf zu trainieren, Hochspannungsleitungen zu verfolgen (z.B. Anwendung für die Inspektion von Energieinfrastrukturen). Hier gibt es sieben diskrete Aktionen, die verschiedenen Richtungen entsprechen, in die sich der Quadrocopter bewegen kann (sechs Richtungen + eine Schweb-Aktion).
def interpret_action(self, action):
if action == 0:
quad_offset = (self.step_length, 0, 0)
elif action == 1:
quad_offset = (0, self.step_length, 0)
elif action == 2:
quad_offset = (0, 0, self.step_length)
elif action == 3:
quad_offset = (-self.step_length, 0, 0)
elif action == 4:
quad_offset = (0, -self.step_length, 0)
elif action == 5:
quad_offset = (0, 0, -self.step_length)
else:
quad_offset = (0, 0, 0)
Die Belohnung ist wieder eine Funktion davon, wie schnell sich der Quadrocopter bewegt, in Verbindung damit, wie weit er sich von den bekannten Stromleitungen entfernt.
def compute_reward(quad_state, quad_vel, collision_info):
thresh_dist = 7
beta = 1
z = -10
pts = [np.array([-0.55265, -31.9786, -19.0225]),np.array([48.59735, -63.3286, -60.07256]),np.array([193.5974, -55.0786, -46.32256]),np.array([369.2474, 35.32137, -62.5725]),np.array([541.3474, 143.6714, -32.07256]),]
quad_pt = np.array(list((self.state["position"].x_val, self.state["position"].y_val,self.state["position"].z_val,)))
if self.state["collision"]:
reward = -100
else:
dist = 10000000
for i in range(0, len(pts) - 1):
dist = min(dist, np.linalg.norm(np.cross((quad_pt - pts[i]), (quad_pt - pts[i + 1]))) / np.linalg.norm(pts[i] - pts[i + 1]))
if dist > thresh_dist:
reward = -10
else:
reward_dist = math.exp(-beta * dist) - 0.5
reward_speed = (np.linalg.norm([self.state["velocity"].x_val, self.state["velocity"].y_val, self.state["velocity"].z_val,])- 0.5)
reward = reward_dist + reward_speed
Wir betrachten eine Episode als beendet, wenn sie sich zu weit von den bekannten Stromleitungs-Koordinaten entfernt, und setzen die Drohne dann auf ihren Startpunkt zurück.
Sobald der Gym-ähnliche Umgebungs-Wrapper wie in drone_env.py definiert ist, verwenden wir Stable Baselines 3, um eine DQN-Trainingsschleife auszuführen. Das DQN-Training kann wie folgt konfiguriert werden, wie in dqn_drone.py zu sehen ist.
model = DQN(
"CnnPolicy",
env,
learning_rate=0.00025,
verbose=1,
batch_size=32,
train_freq=4,
target_update_interval=10000,
learning_starts=10000,
buffer_size=500000,
max_grad_norm=10,
exploration_fraction=0.1,
exploration_final_eps=0.01,
device="cuda",
tensorboard_log="./tb_logs/",
)
Eine Trainingsumgebung und eine Evaluierungsumgebung (siehe EvalCallback in dqn_drone.py) können definiert werden. Die Evaluierungsumgebung kann sich von der Trainingsumgebung unterscheiden und andere Abbruchbedingungen/Szenenkonfigurationen aufweisen. Ein Tensorboard-Logverzeichnis wird ebenfalls als Teil der DQN-Parameter definiert. Schließlich startet model.learn() die DQN-Trainingsschleife. Ähnlich können Implementierungen von PPO, A3C usw. aus Stable Baselines 3 verwendet werden.
Hier ist das Video der ersten paar Episoden während des Trainings.
Verwandt#
Siehe auch The Autonomous Driving Cookbook von Microsoft Deep Learning and Robotics Garage Chapter.

