Week 10 - Conclusion
May 13, 2025
In this final week, we tie together every piece of the project—from configuration and tensor‑based simulation to the interactive visualizer—and reflect on how it all operates as a cohesive system. Along the way, we’ll touch on the subtle clustering patterns that emerge in altruistic mode, but our main focus is on the end‑to‑end mechanics.
1. Project Overview
The goal of this project is to simulate multiple species of agents in a bounded environment, evolving their behaviors via neural networks and genetic algorithms, and observe both competitive and cooperative dynamics. Three species of differing sizes roam a 2D plane collecting food and avoiding mobile chasers. The heart of the system is a PyTorch‑powered evolutionary loop; the crown jewel is a Pygame visualizer that lets us watch it all unfold.
2. Configuration & Initialization
We begin by importing core libraries and defining global parameters:
import torch
import torch.nn.functional as F
import math, time, random, numpy as np
# ENV_SIZE = 1000, FOOD_RADIUS = 2, FOOD_SCORE = 10, EDGE_PENALTY = 2
# NUM_AGENTS = 300, GENERATIONS = 800
# SPECIES_RADII = [6.0, 3.0, 1.5], CHASER_RADIUS = 4.0, CHASER_PENALTY = 30
A master flag, altruism\_enabled
, toggles food‑sharing behavior. The device (CPU/GPU) is detected via torch.device
, ensuring high‑speed tensor ops when CUDA is available.
3. Neural Network & PyTorch Usage
Each agent population is governed by a BatchNeuralNetwork
, a custom 10‑layer feedforward model:
class BatchNeuralNetwork(torch.nn.Module):
def __init__(self, num_agents, input_size=11, hidden_size=12, output_size=4):
super().__init__()
# w1…w11 are Parameter tensors of shape (num_agents, in, out)
torch.nn.init.uniform_(w, -1, 1) # random initialization
def forward(self, x):
x = x.unsqueeze(1)
x = F.relu(torch.bmm(x, self.w1))
…
return x.squeeze(1)
def mutate(self, rate=0.1):
# element‑wise mask and Gaussian noise injection
Key points:
* We vectorize inference across all agents with torch.bmm
, achieving batched matrix multiplications.
* Mutation directly perturbs weights in place for efficient genetic variation.
* All agent states (positions, fitnesses, network weights) live as GPU tensors when possible.
4. Agent Population & Evolutionary Loop
The AgentPopulation
class maintains positions and fitness scores:
class AgentPopulation:
def __init__(self, num_agents, radius):
self.step_size = BASE_STEP_SIZE * (0.5 + 0.5 * sqrt(BASE_RADIUS/radius))
self.positions = torch.rand((num_agents,2))*…
self.fitness = torch.zeros(num_agents)
self.brain = BatchNeuralNetwork(num_agents).to(device)
def evolve(self, mutation_rate):
# select top 10%, copy their weights, then mutate
Every generation:
1. Agents “sense” their environment via proximity tensors to walls, food, other agents, and chasers.
2. The combined feature tensor (shape: num\_agents×11) feeds through the batch network to produce movement decisions.
3. Agents move, incur edge penalties, and collect food if they linger over it for 30 frames.
4. Fitness updates depend on the altruism flag: either proportional sharing or “winner‑takes‑all” stealing.
5. After 600 steps, the top performers seed the next generation via weight copying and mutation.
This loop runs for 3000 (changeable) generations, printing per‑generation statistics and saving out optimized brain weights.
5. Visualization Integration
The StableVisualizerWithSizingALTRUISMSettings.py
brings the simulation to life. Major components:
* Button class: handles drawing, hover detection, and click events for UI controls.
* VisualNeuralNetwork: loads saved weights, optionally adds small variance, and provides a forward
method for single‑agent inference.
* Agent objects: mirror the simulation’s neural inputs and movement logic, but track score
and caught
states for visual feedback.
* Chaser entities: pursue the nearest agent in cardinal directions, penalize caught agents, and “freeze” before hunting again.
* The main loop blends UI event handling (start/pause/reset, altruism toggle, manual placement) with rendering:
* Draw UI panel and buttons.
* Update simulation state if running.
* Render food spots (with a timer arc), agents (with eating/caught indicators), chasers, and live stats.
This separation of concerns—simulation logic in PyTorch vs. rendering logic in Pygame—lets us tweak each independently while maintaining tight synchronization.
6. Clustering in Altruistic Mode
When altruism\_enabled==True
, agents exhibit a subtle clustering behavior around food sources before consumption:
* Because food requires 30 “eating” frames, multiple agents converge and wait together.
* Sharing rewards proportional to size reduces the rush for domination, so smaller agents can safely approach existing clusters.
* The result is visible clusters of mixed‑size agents around each food spot—a vivid contrast to the “scatter‑and‑dash” patterns in stealing mode.
This clustering isn’t explicitly coded; it emerges from the interplay of the eating timer and proportional reward scheme. It’s a powerful demonstration of how simple local rules can generate collective behavior.
7. Project Flow & Data Lifecycle
From start to finish:
1. Configure global parameters and load device.
2. Initialize agent populations and food/chaser objects.
3. Evolve in tight PyTorch loops: sense → decide → move → collect → evolve.
4. Log & Save: print stats, save brain weights each generation.
5. Visualize: load saved brains, spawn Pygame agents, run interactive UI loop.
6. Analyze emergent behaviors like clustering, size‑based dynamics, and chaser‑induced scatter.
Every piece—from uniform weight init to bmm‑based inference, from evolving weight copying to Pygame’s draw calls—works together to create a rich, evolving ecosystem you can both compute and watch in real time.
Conclusion
By combining batched PyTorch inference, evolutionary algorithms, and a flexible Pygame interface, this project delivers a full pipeline: you can train agent brains, observe cooperative vs. competitive strategies, and interact with the simulation via a polished UI.
Leave a Reply
You must be logged in to post a comment.