privateboss's picture
Upload 14 files
323c6ec verified
Raw
History Blame Contribute Delete
6.45 kB
# LINE 1-17: ARE USED TO SILENCE LOGS & ALIGN NAMESPACES
import os
import warnings
import tensorflow as tf
os.environ["TF_USE_LEGACY_KERAS"] = "1"
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
os.environ["TF_FUNCTION_NUMERIC_CHECKS"] = "0"
tf.keras.backend.clear_session()
tf.config.threading.set_intra_op_parallelism_threads(0)
tf.config.threading.set_inter_op_parallelism_threads(0)
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
warnings.filterwarnings("ignore", category=UserWarning, module="gym")
warnings.filterwarnings("ignore", category=RuntimeWarning, module="tf_agents.specs.array_spec")
warnings.filterwarnings("ignore", category=DeprecationWarning)
from tf_agents.agents.ppo import ppo_agent
from tf_agents.networks import network
from tf_agents.networks import categorical_projection_network
from tf_agents.environments import tf_py_environment
# Custom Modular Imports
from config import Config
from env import CyberPettingZooEnv
from utilities import configure_gpu, PettingZooToTFAgentsWrapper
from trainer import MultiAgentTrainer
# BULLETPROOF CUSTOM GNN POLICY NETWORK FOR TF-AGENTS
class CyberGNNNetwork(network.Network):
"""
A custom TF-Agents Network that binds GNN feature extraction with
native CategoricalProjectionNetworks, explicitly forwarding outer_rank.
"""
def __init__(self, input_tensor_spec, output_spec, fc_layer_params=(128, 64), is_value_net=False, name="CyberGNNNetwork"):
super().__init__(input_tensor_spec=input_tensor_spec, state_spec=(), name=name)
self.is_value_net = is_value_net
# 1. Instantiate the Graph Convolution Weights
self.w1 = tf.Variable(tf.keras.initializers.GlorotUniform()(shape=(2, 32)), trainable=True, name="gcn_w1")
self.w2 = tf.Variable(tf.keras.initializers.GlorotUniform()(shape=(32, 32)), trainable=True, name="gcn_w2")
# 2. Instantiate standard Dense MLPs for decision making
self.dense_layers = []
for units in fc_layer_params:
self.dense_layers.append(tf.keras.layers.Dense(units, activation=tf.nn.tanh))
# 3. Instantiate native TF-Agents projection heads
if self.is_value_net:
self.projection_head = tf.keras.layers.Dense(1, kernel_initializer=tf.keras.initializers.Orthogonal(1.0))
else:
self.projection_head = categorical_projection_network.CategoricalProjectionNetwork(output_spec)
def call(self, observations, step_type=(), network_state=(), training=False):
A_norm = observations['adjacency_matrix']
X = observations['node_features']
outer_rank = X.shape.rank - 2
# GNN Message-Passing Block
h1 = tf.nn.tanh(tf.matmul(tf.matmul(A_norm, X), self.w1))
h2 = tf.nn.tanh(tf.matmul(tf.matmul(A_norm, h1), self.w2))
# Dynamically calculate batch structure to prevent rank mismatch crashes
batch_shape = tf.shape(h2)[:-2]
flat_features = tf.reshape(h2, tf.concat([batch_shape, [-1]], axis=0))
# Standard Policy Dense Layer Block
x = flat_features
for layer in self.dense_layers:
x = layer(x)
# Output Generation Pass
if self.is_value_net:
value_predictions = self.projection_head(x)
value_predictions = tf.squeeze(value_predictions, axis=-1)
return value_predictions, network_state
else:
action_distributions, _ = self.projection_head(x, outer_rank=outer_rank, training=training)
return action_distributions, network_state
# AGENT BUILD ORCHESTRATION WITH EXPLICIT VARIABLE REGISTRATION
def create_ppo_agent(env_time_step_spec, env_action_spec, agent_name, lr_schedule):
"""Creates an independent PPO Agent with guaranteed trainable variable tracking."""
agent_obs_spec = env_time_step_spec.observation[agent_name]
agent_action_spec = env_action_spec[agent_name]
actor_net = CyberGNNNetwork(
input_tensor_spec=agent_obs_spec,
output_spec=agent_action_spec,
fc_layer_params=Config.ACTOR_LAYERS,
is_value_net=False,
name=f"actor_gnn_{agent_name}"
)
value_net = CyberGNNNetwork(
input_tensor_spec=agent_obs_spec,
output_spec=None,
fc_layer_params=Config.CRITIC_LAYERS,
is_value_net=True,
name=f"value_gnn_{agent_name}"
)
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)
agent = ppo_agent.PPOAgent(
time_step_spec=env_time_step_spec._replace(
observation=agent_obs_spec,
reward=env_time_step_spec.reward[agent_name]
),
action_spec=agent_action_spec,
optimizer=optimizer,
actor_net=actor_net,
value_net=value_net,
num_epochs=10,
discount_factor=Config.GAMMA,
use_gae=True,
use_td_lambda_return=True,
normalize_observations=False,
normalize_rewards=True,
value_pred_loss_coef=0.5
)
agent.initialize()
print(f"🔒 Verified Trainable Variables for {agent_name} Actor: {len(actor_net.trainable_variables)}")
return agent
# MAIN RUNTIME EXECUTION LOOP
def main():
configure_gpu()
print(f"🚀 Initializing Custom GNN MARL Cyber Range Framework in **{Config.MODE}** mode.")
raw_pz_env = CyberPettingZooEnv()
py_env = PettingZooToTFAgentsWrapper(raw_pz_env)
tf_env = tf_py_environment.TFPyEnvironment(py_env)
time_step_spec = tf_env.time_step_spec()
action_spec = tf_env.action_spec()
print("🧠 Constructing Custom Graph Policy Networks for Red Agent...")
red_agent = create_ppo_agent(time_step_spec, action_spec, 'red', Config.get_red_lr_schedule())
print("🧠 Constructing Custom Graph Policy Networks for Blue Agent...")
blue_agent = create_ppo_agent(time_step_spec, action_spec, 'blue', Config.get_blue_lr_schedule())
trainer = MultiAgentTrainer(config=Config, tf_env=tf_env, agent_1=red_agent, agent_2=blue_agent)
print("✨ Graph Neural Network pipeline successfully compiled. Launching training loop...")
for epoch in range(1, Config.TOTAL_EPISODES + 1):
trainer.train_epoch(epoch_idx=epoch)
if __name__ == '__main__':
main()