agentic-drone-tuner / inference.py
alkshatraj's picture
fix: provide task graders, correct step return signature, remove meta headers
bc9492f
Raw
History Blame Contribute Delete
5.81 kB
#
# This source code is licensed under the BSD-style license found in the
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from trl import GRPOTrainer, GRPOConfig
from openenv.core.generic_client import GenericEnvClient
import numpy as np
import re
import os
from openai import OpenAI
# --- TRL and GRPO Setup ---
def get_reward(rmse):
"""Calculates reward based on RMSE."""
return float(np.exp(-0.1 * rmse))
def extract_pid_from_text(text):
"""Extracts PID values from the LLM's output using regex."""
try:
p_match = re.search(r"P:\s*([\d\.]+)", text)
i_match = re.search(r"I:\s*([\d\.]+)", text)
d_match = re.search(r"D:\s*([\d\.]+)", text)
p = float(p_match.group(1)) if p_match else 0.0
i = float(i_match.group(1)) if i_match else 0.0
d = float(d_match.group(1)) if d_match else 0.0
return {"Kp": p, "Ki": i, "Kd": d}
except (AttributeError, ValueError):
# Return default values if parsing fails
return {"Kp": 1.0, "Ki": 0.1, "Kd": 0.5}
def run_grpo_tuning():
"""
Main function to run the GRPO training loop.
This is a simplified example and would require a more robust implementation for real train
ing.
"""
# 1. Initialize Environment Client
# NOTE: The environment server might be running on localhost during proxy evaluation. We check OPENENV_BASE_URL if it's separate from API_BASE_URL.
env_base_url = os.environ.get("OPENENV_BASE_URL", "http://127.0.0.1:7860")
try:
async_client = GenericEnvClient(base_url=env_base_url)
client = async_client.sync()
except Exception as e:
print(f"Failed to connect to environment server at {env_base_url}: {e}")
return
# 2. Load a Pre-trained LLM and Tokenizer
model_name = "gpt2" # Using gpt2 for simplicity, but a larger model is recommended
# Initialize OpenAI client using competition injected variables
llm_api_base = os.environ.get("API_BASE_URL", "https://api.groq.com/openai/v1")
llm_api_key = os.environ.get("API_KEY", os.environ.get("HF_TOKEN", "dummy_key"))
llm_model = os.environ.get("MODEL_NAME", "llama3")
openai_client = OpenAI(
base_url=llm_api_base,
api_key=llm_api_key
)
# Run through the tasks defined in openenv.yaml
tasks = [
{"id": "stability_easy", "target_altitude": 50.0, "mass": 1.0, "base_wind": -5.0},
{"id": "payload_medium", "target_altitude": 100.0, "mass": 2.0, "base_wind": -10.0},
{"id": "stormy_hard", "target_altitude": 150.0, "mass": 0.5, "base_wind": -15.0}
]
for task_info in tasks:
task_id = task_info["id"]
target_altitude = task_info["target_altitude"]
base_wind = task_info["base_wind"]
print(f"[START] task={task_id}", flush=True)
try:
client.reset(params=task_info)
except Exception as e:
print(f"Error during reset: {e}")
continue
# run 5 tuning episodes for each task
best_reward = 0.0
for episode in range(5):
# a. Create the Prompt
prompt_text = f"Mission: Reach {target_altitude:.0f}m altitude. Wind is {base_wind:.0f}N. Predict PID gains. Format: P: X.XX, I: Y.YY, D: Z.ZZ"
# b. Generate completions using OpenAI Proxy instead of local model
try:
response = openai_client.chat.completions.create(
model=llm_model,
messages=[
{"role": "system", "content": "You are a PID tuning expert. Provide PID gains."},
{"role": "user", "content": prompt_text}
],
max_tokens=50,
temperature=0.7
)
text = response.choices[0].message.content
except Exception as e:
print(f"Error calling LLM: {e}")
text = ""
pid_params = extract_pid_from_text(text)
# c. Evaluate step
try:
obs, reward, done, info = client.step(pid_params)
except Exception as e:
print(f"Error during step: {e}")
reward = 0.0
print(f"[STEP] step={episode+1} reward={reward:.4f}", flush=True)
if reward > best_reward:
best_reward = reward
# Ensure the score is strictly between 0 and 1 as required by the validator
final_score = max(0.001, min(0.999, best_reward))
print(f"[END] task={task_id} score={final_score:.4f} steps=5", flush=True)
print("\nGRPO Tuning Complete.", flush=True)
# The environment variables must be defined as per Round 1 rules.
API_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.groq.com/openai/v1")
MODEL_NAME = os.environ.get("MODEL_NAME", "llama3-70b-8192")
HF_TOKEN = os.environ.get("HF_TOKEN")
API_KEY = os.environ.get("OPENAI_API_KEY")
# Task Definitions (Match openenv.yaml)
TASK_DEFINITIONS = {
"drone_mission": {
"mission": "drone_mission",
"params": {
"altitude": {"type": "float", "min": 0, "max": 1000},
"wind": {"type": "float", "min": -100, "max": 100},
},
},
}
if __name__ == "__main__":
print("Starting Agentic Drone PID Tuner Inference...")
print("NOTE: Ensure the OpenEnv server is running for 'drone_env'.")
print("`openenv-server --env drone_env`")
# This example focuses on the GRPO loop. A full implementation would
# separate training and inference more cleanly.
run_grpo_tuning()