communitypulse-env / train.py
Bhumss12's picture
update
a9d8689
Raw
History Blame Contribute Delete
10.3 kB
"""
Training script for NGO Multi-Agent Coordination Environment
Trains agents using simple Q-learning approach
"""
import numpy as np
import matplotlib.pyplot as plt
from typing import List, Tuple, Dict
import json
from ngo_coordination_env import NGOCoordinationEnv
class SimpleRLAgent:
"""
Simple Q-learning based agent for demonstration
In production, you'd use PPO, SAC, or MADDPG from Stable-Baselines3
"""
def __init__(self, action_dim: int = 3, learning_rate: float = 0.01):
self.lr = learning_rate
self.action_dim = action_dim
# Initialize policy parameters (simple neural network weights)
self.theta = np.random.randn(action_dim) * 0.1
# Exploration parameters
self.epsilon = 1.0 # Start with high exploration
self.epsilon_decay = 0.995
self.epsilon_min = 0.05
def select_action(self, observation: Dict, explore: bool = True) -> np.ndarray:
"""Select action using epsilon-greedy strategy"""
# Extract state features
urgency = observation['urgency'] / 10.0
resources = observation['available_resources'][0] / 100.0
people = observation['people_affected'][0] / 300.0
# Simple feature vector
state_features = np.array([urgency, resources, people])
if explore and np.random.random() < self.epsilon:
# Explore: random action
action = np.random.uniform(0, 1, size=self.action_dim)
else:
# Exploit: use learned policy
# Simple linear policy: action = sigmoid(theta * features)
raw_action = self.theta * np.mean(state_features)
action = 1.0 / (1.0 + np.exp(-raw_action)) # Sigmoid
action = np.clip(action, 0, 1)
return action
def update(self, observation: Dict, action: np.ndarray, reward: float, next_observation: Dict):
"""Update policy based on experience"""
# Simple policy gradient update
# In practice, use proper RL algorithms (PPO, SAC, etc.)
# Gradient direction: increase probability of actions that gave high reward
gradient = reward * action * 0.01
self.theta += self.lr * np.mean(gradient)
# Decay exploration
self.epsilon = max(self.epsilon * self.epsilon_decay, self.epsilon_min)
def train_multi_agent_system(
num_episodes: int = 100,
max_steps: int = 50,
num_agents: int = 3
) -> Tuple[List[float], List[Dict]]:
"""
Train multiple agents in the NGO coordination environment
Returns:
rewards_history: List of total rewards per episode
info_history: Detailed logs for analysis
"""
# Create environment
env = NGOCoordinationEnv(num_agents=num_agents, max_steps=max_steps)
# Create agents
agents = [SimpleRLAgent(action_dim=3) for _ in range(num_agents)]
# Training history
rewards_history = []
info_history = []
print("Starting Multi-Agent Training...")
print(f"Episodes: {num_episodes}, Max Steps: {max_steps}, Agents: {num_agents}\n")
for episode in range(num_episodes):
observation, info = env.reset()
episode_reward = 0
episode_info = {
'episode': episode + 1,
'steps': [],
'task_type': info['task_type']
}
for step in range(max_steps):
# Each agent selects action
actions = np.vstack([agent.select_action(observation, explore=True)
for agent in agents])
# Environment step
next_observation, reward, terminated, truncated, step_info = env.step(actions)
# Update agents
for i, agent in enumerate(agents):
agent.update(observation, actions[i], reward, next_observation)
# Track progress
episode_reward += reward
episode_info['steps'].append({
'step': step + 1,
'reward': reward,
'allocations': step_info['allocations'].tolist()
})
observation = next_observation
if terminated or truncated:
break
rewards_history.append(episode_reward)
info_history.append(episode_info)
# Print progress
if (episode + 1) % 10 == 0:
avg_reward = np.mean(rewards_history[-10:])
print(f"Episode {episode + 1}/{num_episodes} | "
f"Avg Reward (last 10): {avg_reward:.2f} | "
f"Task: {info['task_type']}")
print("\nTraining Complete!")
return rewards_history, info_history
def plot_learning_curves(rewards_history: List[float], info_history: List[Dict]):
"""Generate the 3 required visualizations"""
# Calculate cumulative steps
cumulative_steps = []
total = 0
for info in info_history:
for step_info in info['steps']:
total += 1
cumulative_steps.append(total)
# Extract all step rewards
all_rewards = []
for info in info_history:
for step_info in info['steps']:
all_rewards.append(step_info['reward'])
# 1. OVERALL LEARNING CURVE
plt.figure(figsize=(12, 6))
plt.scatter(cumulative_steps, all_rewards, alpha=0.5, s=20, label='Step Rewards', color='green')
# Smooth curve
from scipy.ndimage import gaussian_filter1d
if len(all_rewards) > 10:
smoothed = gaussian_filter1d(all_rewards, sigma=5)
plt.plot(cumulative_steps, smoothed, color='darkgreen', linewidth=2, label='Learning Curve')
# Trend line
z = np.polyfit(cumulative_steps, all_rewards, 1)
p = np.poly1d(z)
plt.plot(cumulative_steps, p(cumulative_steps), "--", color='blue', linewidth=2, label='Trend')
plt.xlabel('Step Number', fontsize=12)
plt.ylabel('Reward', fontsize=12)
plt.title('Multi-Agent Learning Curve - Overall Progress', fontsize=14, fontweight='bold')
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('results/overall_learning_curve.png', dpi=150)
print("Saved: results/overall_learning_curve.png")
# 2. TASK COMPARISON (4 subplots)
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()
task_types = ['cooperation', 'competition', 'negotiation', 'coalition']
colors = ['blue', 'green', 'orange', 'red']
for idx, task_type in enumerate(task_types):
# Filter episodes for this task
task_episodes = [info for info in info_history if info['task_type'] == task_type]
task_rewards = []
task_steps = []
step_counter = 0
for ep_info in task_episodes:
for step_info in ep_info['steps']:
task_rewards.append(step_info['reward'])
task_steps.append(step_counter)
step_counter += 1
if task_rewards:
axes[idx].scatter(task_steps, task_rewards, alpha=0.6, s=15, color=colors[idx])
if len(task_rewards) > 5:
smoothed = gaussian_filter1d(task_rewards, sigma=3)
axes[idx].plot(task_steps, smoothed, color=colors[idx], linewidth=2)
axes[idx].set_title(f'Task: {task_type.capitalize()}', fontweight='bold')
axes[idx].set_xlabel('Step')
axes[idx].set_ylabel('Reward')
axes[idx].grid(alpha=0.3)
plt.tight_layout()
plt.savefig('results/task_comparison.png', dpi=150)
print("Saved: results/task_comparison.png")
# 3. TASK PROGRESSION (bar chart)
plt.figure(figsize=(10, 6))
task_avg_rewards = []
for task_type in task_types:
task_rewards = []
for info in info_history:
if info['task_type'] == task_type:
for step_info in info['steps']:
task_rewards.append(step_info['reward'])
task_avg_rewards.append(np.mean(task_rewards) if task_rewards else 0)
bars = plt.bar(range(len(task_types)), task_avg_rewards, color=colors, alpha=0.7, edgecolor='black')
# Add value labels on bars
for i, (bar, val) in enumerate(zip(bars, task_avg_rewards)):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.5,
f'{val:.2f}', ha='center', fontweight='bold')
plt.xlabel('Task Type', fontsize=12)
plt.ylabel('Average Reward', fontsize=12)
plt.title('Task Progression - Average Rewards', fontsize=14, fontweight='bold')
plt.xticks(range(len(task_types)), [t.capitalize() for t in task_types])
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('results/task_progression.png', dpi=150)
print("Saved: results/task_progression.png")
plt.close('all')
def main():
"""Main execution"""
# Create results directory
import os
os.makedirs('results', exist_ok=True)
# Train agents
rewards_history, info_history = train_multi_agent_system(
num_episodes=100, # 100 episodes total
max_steps=50, # 50 steps per episode
num_agents=3 # 3 agents
)
# Generate visualizations
print("\nGenerating Visualizations...")
plot_learning_curves(rewards_history, info_history)
# Save training data
with open('results/training_results.json', 'w') as f:
json.dump({
'rewards_history': rewards_history,
'info_history': info_history
}, f, indent=2)
print("Saved: results/training_results.json")
# Print summary statistics
print("\n" + "="*60)
print("TRAINING SUMMARY")
print("="*60)
print(f"Total Episodes: {len(rewards_history)}")
print(f"First 10 Episodes Avg Reward: {np.mean(rewards_history[:10]):.2f}")
print(f"Last 10 Episodes Avg Reward: {np.mean(rewards_history[-10:]):.2f}")
improvement = ((np.mean(rewards_history[-10:]) - np.mean(rewards_history[:10])) /
np.mean(rewards_history[:10]) * 100)
print(f"Improvement: {improvement:.1f}%")
print("="*60)
if __name__ == "__main__":
main()