주뇽's 저장소

[CODE 리뷰]Dealing with Changes: Resilient Routing via Graph Neural Networks and Multi-Agent Deep Reinforcement Learning 본문

GNN

[CODE 리뷰]Dealing with Changes: Resilient Routing via Graph Neural Networks and Multi-Agent Deep Reinforcement Learning

뎁쭌 2023. 10. 17. 21:21
728x90
반응형

2023.10.17 - [DeepLearning/Paper Riview] - Dealing with Changes: Resilient Routing via Graph Neural Networks and Multi-Agent Deep Reinforcement Learning 논문 리뷰

 

Dealing with Changes: Resilient Routing via Graph Neural Networks and Multi-Agent Deep Reinforcement Learning 논문 리뷰

• Bhavanasi S S, Pappone L, Esposito F. Dealing with Changes: Resilient Routing via Graph Neural Networks and Multi-Agent Deep Reinforcement Learning[J]. IEEE Transactions on Network and Service Management, 2023. Link Code 변화에 대처하기: 그래

jypark1111.tistory.com

https://github.com/routing-drl/main/

 

 

GitHub - routing-drl/main

Contribute to routing-drl/main development by creating an account on GitHub.

github.com

DQN.py

# 필요한 라이브러리와 모듈을 임포트합니다.
import math
import random
import numpy as np
import matplotlib.pyplot as plt
from collections import namedtuple
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

# GPU가 사용 가능한 경우 CUDA를 사용하고, 그렇지 않으면 CPU를 사용합니다.
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 에이전트의 경험을 저장하기 위한 데이터 구조를 정의합니다.
Transition = namedtuple('Transition', ('state', 'action', 'next_state', 'reward'))

# 경험 재생(Experience Replay)을 위한 메모리 클래스입니다.
class ReplayMemory(object):
    def __init__(self, capacity):
        self.capacity = capacity  # 메모리의 최대 용량
        self.memory = []  # 경험을 저장할 리스트
        self.random_memory = []  # 초기 무작위 움직임을 저장할 리스트
        self.position = 0  # 현재 저장 위치
        self.num_pushes = 0  # 저장된 경험의 총 수

    def push(self, *args):
        """경험을 메모리에 저장합니다."""
        if len(self.memory) < self.capacity:
            self.memory.append(None)
            self.random_memory.append(None)
        self.memory[self.position] = Transition(*args)
        if self.num_pushes < 2*self.capacity:
            self.random_memory[self.position] = Transition(*args)
        self.position = (self.position + 1) % self.capacity
        self.num_pushes += 1

    def sample(self, batch_size):
        """메모리에서 무작위로 경험을 샘플링합니다."""
        return random.sample(self.memory, batch_size)

    def regular_sample(self, batch_size):
        """정규화된 경험과 무작위 경험을 함께 샘플링합니다."""
        regular_memory_batch_size = int(batch_size*.7)
        random_memory_batch_size = batch_size - regular_memory_batch_size
        return random.sample(self.memory, regular_memory_batch_size) + random.sample(self.random_memory, random_memory_batch_size)

    def __len__(self):
        return len(self.memory)

# DQN 신경망 모델을 정의합니다.
class DQN(nn.Module):
    def __init__(self, inputs, outputs):
        super(DQN, self).__init__()
        val = int((inputs+outputs)/2)
        self.fc1 = nn.Linear(inputs, val)
        self.fc2 = nn.Linear(val, val)
        self.fc3 = nn.Linear(val, val)
        self.fc4 = nn.Linear(val, outputs)

    def forward(self, x):
        """신경망의 순전파를 정의합니다."""
        x = x.float()
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        return F.log_softmax(self.fc4(x), dim=1)

# 학습에 사용될 하이퍼파라미터를 정의합니다.
BATCH_SIZE = 64*3
GAMMA = 0.999
EPS_START = 1
EPS_END = 0.01
TARGET_UPDATE = 1
STEP_MULTIPLIER = 600

# 에이전트의 행동과 학습을 관리하는 클래스를 정의합니다.
class Agent():
    def __init__(self, outputs, policy_net, target_net):
        self.n_actions = outputs  # 가능한 행동의 수
        self.policy_net = policy_net  # 정책 신경망
        self.target_net = target_net  # 타깃 신경망
        self.target_net.load_state_dict(self.policy_net.state_dict())
        self.target_net.eval()  # 타깃 신경망은 학습 모드가 아닌 평가 모드로 설정
        self.optimizer = optim.RMSprop(self.policy_net.parameters())
        self.memory = ReplayMemory(2_000)  # 경험 재생 메모리
        self.steps_done = 0  # 총 수행된 스텝 수
        self.episode_durations = []  # 각 에피소드의 지속 시간을 저장
        self.lossDat = []  # 손실 데이터를 저장
        self.steps = 0  # 현재 에피소드에서의 스텝 수
        self.eps = .9  # 엡실론 그리디 정책의 엡실론 값
        self.epsilon_decay = 75*1000  # 엡실론 감소율

    def select_action(self, state):
        """엡실론 그리디 정책을 사용하여 행동을 선택합니다."""
        sample = random.random()
        eps_threshold = EPS_END + (EPS_START - EPS_END) * math.exp(-1. * self.steps_done / self.epsilon_decay)
        self.steps_done += STEP_MULTIPLIER
        if sample > eps_threshold:
            with torch.no_grad():
                return self.policy_net(state).max(1)[1].view(1, 1)
        else:
            return torch.as_tensor([[random.randrange(self.n_actions)]], device=device, dtype=torch.long)

    def predict(self, state):
        """타깃 신경망을 사용하여 다음 상태의 행동 값을 예측합니다."""
        return self.target_net(state).max(1)[1].view(1, 1)

    def optimize_model(self):
        if len(self.memory) < BATCH_SIZE:
            return
        transitions = self.memory.sample(BATCH_SIZE)
        batch = Transition(*zip(*transitions))

        non_final_mask = torch.as_tensor(tuple(map(lambda s: s is not None,
                                                   batch.next_state)), device=device, dtype=torch.bool)
        non_final_next_states = torch.cat([s for s in batch.next_state
                                           if s is not None])

        state_batch = torch.cat(batch.state)
        action_batch = torch.cat(batch.action)
        reward_batch = torch.cat(batch.reward)

        state_action_values = self.policy_net(
            state_batch).gather(1, action_batch)

        next_state_values = torch.zeros(BATCH_SIZE, device=device)
        next_state_values[non_final_mask] = self.target_net(
            non_final_next_states).max(1)[0].detach()

        expected_state_action_values = (
            next_state_values * GAMMA) + reward_batch

        # Compute Huber loss
        loss = F.smooth_l1_loss(state_action_values,
                                expected_state_action_values.unsqueeze(1))

        # Optimize the model
        self.optimizer.zero_grad()
        loss.backward()
        for param in self.policy_net.parameters():
            param.grad.data.clamp_(-1, 1)
        self.optimizer.step()

class MultiAgent():

    def __init__(self, env):

        self.env = env
        self.num_agents = int(self.env.observation_space.nvec[0])
        self.agents = []
        self.nodes = list(self.env.graph.nodes)
        self.initialize()

    def initialize(self):
        for i in range(len(self.nodes)):
            # inputs - 1 hot dest, outputs - num neighbors
            num_inputs = self.num_agents
            num_outs = len(list(self.env.graph.neighbors(self.nodes[i])))
            self.agents.append(
                Agent(
                    num_outs,
                    DQN(num_inputs, num_outs).to(device),
                    DQN(num_inputs, num_outs).to(device)
                ))

    def _format_input(self, input):
        '''Given destination:int return one hot destination'''
        try:
            arr = np.zeros(shape=(1, self.num_agents))

            arr[0][self.nodes.index(input)] = 1

            arr = torch.from_numpy(arr)

        except Exception as e:
            print("error:", input, arr, e)
        return arr

    def run(self, episodes=100):

        for i in range(episodes):
            obs, done = self.env.reset(), False
            curr_agent = self.nodes.index(obs[0])
            state = self._format_input(obs[1])
            rews = 0
            while not done:
                action = self.agents[curr_agent].select_action(state)
                obs, reward, done, infos = self.env.step(action.item())
                rews += reward
                reward = torch.as_tensor([reward], device=device)

                if not done:
                    next_state = self._format_input(obs[1])
                else:
                    next_state = None

                self.agents[curr_agent].memory.push(
                    state, action, next_state, reward)

                state = next_state

                self.agents[curr_agent].optimize_model()

                curr_agent = self.nodes.index(obs[0])
            # Update the target network, copying all weights and biases in DQN
            if i % TARGET_UPDATE == 0:
                for j in range(len(self.agents)):
                    self.agents[j].target_net.load_state_dict(
                        self.agents[j].policy_net.state_dict())
            if i % 500 == 0:
                print(i, rews)

    def test(self, num_episodes=350):
        good = 0
        bad = 0
        for _ in range(num_episodes):
            obs, done = self.env.reset(), False
            curr_node = obs[0]
            curr_agent = self.nodes.index(obs[0])

            obs = self._format_input(obs[1])
            rews = 0
            while not done:
                with torch.no_grad():
                    action = self.agents[curr_agent].predict(obs)
                    while action >= len(list(self.env.graph.neighbors(curr_node))):
                        action = torch.as_tensor(
                            [[random.randint(0, len(list(self.env.graph.neighbors(curr_node)))-1)]])
                    obs, reward, done, infos = self.env.step(
                        action.item(), train_mode=False)
                    rews += reward
                    curr_node = obs[0]
                    curr_agent = self.nodes.index(obs[0])
                    obs = self._format_input(obs[1])
            if reward == 1.01 or reward == -1.51:
                good += 1
            else:
                bad += 1
        print(f"%dqn Routed: {good / float(good + bad)} {good} {bad}"))

💡 예시


상황: 새로운 도시에 왔다. 이 도시에는 여러 건물과 길들이 있으며, 목표는 특정 건물에서 다른 건물로 최대한 빠르게 이동하는 것이다. 처음에는 도시의 지도를 모르기 때문에 무작위로 길을 선택하여 목적지를 향해 이동한다.

  1. 초기화 (__init__ 메서드 in ReplayMemory, DQN, Agent, MultiAgent):
    • 현재의 모델(신경망, DQN)은 아무런 지식이 없으므로 무작위로 길을 선택한다.
    • 모델은 여러 경험(Transition)을 기억하기 위해 메모리(ReplayMemory)를 갖고 있다.
    • 도시의 각 건물에는 안내원(Agent)이 있어, 당신에게 어떤 길로 가야 할지 조언을 해준다.
  2. 길 선택 (select_action 메서드 in Agent):
    • 현재 위치에서 가능한 모든 길을 고려하여 길을 선택한다.
    • 초기에는 도시를 잘 모르기 때문에 무작위로 길을 선택한다. 하지만 시간이 지나면서 좋은 경험과 나쁜 경험을 기억하게 되며, 이를 바탕으로 더 나은 길을 선택하게 된다.
  3. 경험 저장 (push 메서드 in ReplayMemory):
    • 선택한 길을 따라 이동하면서 경험을 얻는다. (예: 이 길은 막히지 않았다, 이 길은 시간이 오래 걸렸다 등)
    • 이 경험은 메모리에 저장된다.
  4. 학습 (optimize_model 메서드 in Agent):
    • 모델은 주기적으로 메모리에서 경험을 무작위로 추출하여 과거의 경험에서 학습한다.
    • 이를 통해 모델은 어떤 길이 좋고 어떤 길이 나쁜지를 판단하는 능력을 향상시킨다.
  5. 목적지 도착 (run 메서드 in MultiAgent):
    • 모델은 목적지에 도착하면 이번 여정에서의 전체 경험을 평가하고, 다음 여정을 위해 준비한다.

이렇게 모델은 도시의 길을 점점 더 잘 알게 되고, 더 빠르게 목적지에 도착할 수 있는 최적의 길을 찾아간다. 이러한 과정은 코드에서 에이전트가 환경과 상호작용하며 학습하는 과정과 유사하다.

GCN.py

# 필요한 라이브러리와 모듈을 임포트합니다.
from tqdm import tqdm
from itertools import count
import random
from torch_geometric.nn import GATConv
from torch_geometric.loader import DataLoader
import torch.nn.functional as F
from torch import nn
import torch
import math
from models.DQN import GAMMA, Agent, Transition, ReplayMemory
from torch.optim.lr_scheduler import StepLR
from config import device
import pandas as pd

# 하이퍼파라미터를 설정합니다.
TARGET_UPDATE = 14_000
EPS_DECAY = 17_000
EPS_START = .95
BATCH_SIZE = 128
EPS_END = 0.001
GAMMA = 0.99

# GAT를 활용한 그래프 컨볼루션 네트워크 (GCN) 모델을 정의합니다.
class GCN(nn.Module):
    def __init__(self, num_nodes, out):
        super().__init__()
        conv1_out = num_nodes//3
        conv2_out = num_nodes//2

        # GAT 계층을 정의합니다.
        self.conv1 = GATConv(3, conv1_out, edge_dim=1)
        self.conv2 = GATConv(conv1_out, conv2_out, edge_dim=1)

        # 완전 연결 계층 (Fully Connected Layer)를 정의합니다.
        self.x1 = nn.Linear(num_nodes*conv2_out, num_nodes)
        self.x2 = nn.Linear(num_nodes, out)

        self.num_nodes = num_nodes

    def forward(self, state):
        loader: DataLoader = state[0]
        mask = state[1]

        for batch in loader:
            out = self.conv1(batch.x, batch.edge_index, batch.edge_attr)
            out = torch.selu(out)
            out = self.conv2(out, batch.edge_index, batch.edge_attr)
        out = torch.stack(out.split(self.num_nodes))
        out = out.flatten(start_dim=1)
        conv_out = torch.selu(out)
        x = self.x1(conv_out)
        x = torch.selu(x)
        x = self.x2(x)

        x[~mask] = float('-inf')

        return x
recorder = [0, 0]

# Agent 클래스를 상속받아 GCN을 활용한 강화 학습 에이전트를 정의합니다.
class GCN_Agent(Agent):
    # 초기화 함수
    def __init__(self, outputs, policy_net, target_net, num_nodes, env):
        super().__init__(outputs, policy_net, target_net)
        self.num_nodes = num_nodes  # 그래프의 노드 수
        self.env = env  # 환경
        self.memory = ReplayMemory(3_000)  # 리플레이 메모리
        self.steps_done = 0  # 수행된 스텝 수
        # 옵티마이저로 Adam을 사용
        self.optimizer = torch.optim.Adam(self.policy_net.parameters(), lr=0.001)
        # 학습률 스케줄러
        self.scheduler = StepLR(self.optimizer, step_size=80, gamma=.9)
        # 학습 중에 기록할 메트릭들
        self.metrics = {
            'loss': [],
            'reward': [],
            'path_length': [],
            'eps_reward': []
        }

    def select_action(self, state):
        sample = random.random()
        eps_threshold = EPS_END + (EPS_START - EPS_END) * \
            math.exp(-1. * self.steps_done / EPS_DECAY)

        if sample > eps_threshold:
            state_as_loader = DataLoader(
                [state[0]], batch_size=1, shuffle=False)
            recorder[0] += 1
            with torch.no_grad():
                self.policy_net.eval()
                action = self.policy_net((state_as_loader, state[1])).max(1)[
                    1].view(1, 1)
                self.policy_net.train()
                return action

        else:
            recorder[1] += 1

            mask = state[1][0]
            indices = (mask == True).nonzero().flatten()
            random_action = indices[torch.randint(
                0, indices.shape[0], size=(1, 1))]

            return random_action

    def _format_input(self, state):
        """
        state here is (src,tgt,mask) where src, tgt are ints and mask is an array
        """
        src_tgt_mat = torch.zeros(size=(self.num_nodes, 2), device=device)
        src_tgt_mat[state[0]][0] = 1  # src
        src_tgt_mat[state[1]][1] = 1  # tgt
        return torch.unsqueeze(src_tgt_mat, 0)

    def optimize_model(self):
        if len(self.memory) < BATCH_SIZE:
            self.steps_done = 0
            return
        transitions = self.memory.sample(BATCH_SIZE)
        batch = Transition(*zip(*transitions))

        non_final_mask = torch.as_tensor(tuple(map(lambda s: s is not None,
                                                   batch.next_state)), device=device, dtype=torch.bool)

        non_final_next_graph_list = [s[0]
                                     for s in batch.next_state if s is not None]
        non_final_next_states = (DataLoader(non_final_next_graph_list, batch_size=len(
            non_final_next_graph_list), shuffle=False),
            torch.cat([s[1] for s in batch.next_state if s is not None]))
        state_batch_graph_list = [s[0] for s in batch.state]
        state_batch = (DataLoader(state_batch_graph_list, batch_size=len(
            state_batch_graph_list), shuffle=False),
            torch.cat([s[1] for s in batch.state]))

        action_batch = torch.cat(batch.action)
        reward_batch = torch.cat(batch.reward)
        state_action_values = self.policy_net(
            state_batch).gather(1, action_batch)

        next_state_values = torch.zeros(BATCH_SIZE, device=device)
        next_state_values[non_final_mask] = self.target_net(
            non_final_next_states).max(1)[0].detach()
        # Compute the expected Q values
        expected_state_action_values = (
            next_state_values * GAMMA) + reward_batch

        # Compute Huber loss
        loss = F.smooth_l1_loss(state_action_values,
                                expected_state_action_values.unsqueeze(1))
        self.metrics['loss'].append(loss.item())
        self.optimizer.zero_grad()
        loss.backward()

        for param in self.policy_net.parameters():
            param.grad.data.clamp_(-1, 1)
        self.optimizer.step()

    def update_lr(self):
        for g in self.optimizer.param_groups:
            g['lr'] = 0.001

    def run(self, num_episodes=1000):
        step_count = 0
        global recorder
        for i_episode in tqdm(range(num_episodes), position=0, leave=True):
            # Initialize the environment and state
            _state, data = self.env.reset()
            mask = data['valid_actions']
            state = _state, mask
            eps_rew = 0

            for t in count():
                step_count += 1
                self.steps_done += 1

                action = self.select_action(state)
                _next_state, reward, done, data = self.env.step(action.item())
                eps_rew += reward
                self.metrics['reward'].append(reward)

                next_state_mask = data['valid_actions']

                next_state = _next_state, next_state_mask

                reward = torch.tensor([reward], device=device)

                if done:
                    next_state = None

                # Store the transition in memory
                self.memory.push(state, action, next_state, reward)

                # Move to the next state
                state = next_state

                self.optimize_model()

                if done:
                    self.episode_durations.append(t + 1)
                    self.metrics['path_length'].append(t+1)
                    self.metrics['eps_reward'].append(eps_rew)

                    break
                # Update the target network, copying all weights and biases in DQN
                if step_count % TARGET_UPDATE == 0:
                    self.target_net.load_state_dict(
                        self.policy_net.state_dict())
                    # print("here")
            self.scheduler.step()

            if i_episode % 50 == 0:
                print(i_episode, self.steps_done, reward)
                metrics = pd.DataFrame(
                    dict([(k, pd.Series(v)) for k, v in self.metrics.items()]))

                print(metrics.describe().loc[[
                      'count', 'mean', '50%', '25%', '75%']])
                self.metrics = {
                    'loss': [],
                    'reward': [],
                    'path_length': [],
                    'eps_reward': []
                }
                print("decay:", recorder[0]/sum(recorder))
                print("lr:", self.scheduler.get_last_lr())
                recorder = [0, 0]
                print("-"*50)

Train.py

# 필요한 라이브러리 및 모듈을 임포트합니다.
from helper.graph import compute_flow_value
import networkx as nx
from environment.util import create_graph, get_flows, adjust_lat_band
import os
from environment.env import Env as link_hop_env
from models.DQN import *
import time
from models.GCN import GCN_Agent, GCN
from environment.GCN_env import Env
directory = "training_data"

# 훈련 데이터를 저장할 디렉토리를 생성합니다.
if not os.path.exists(directory):
    os.makedirs(directory)

# (선택 사항) 재현성을 위해 시드를 설정할 수 있습니다.
# torch.manual_seed(1)
# np.random_seed(1)
# random.seed(1)
# torch.cpu.manual_seed(1)

lwr = -1.51  # 보상 함수를 기반으로 모델을 평가할 때 사용되는 값

# Multi-Agent DQN 알고리즘을 실행하는 함수
def ma():
    t0 = time.time()
    contn = "yes"
    # 환경을 초기화합니다.
    env = link_hop_env(directory + "/" + "50Nodes_wax" + ".csv",  G)
    env.graph = adjust_lat_band(env.graph, flows)
    model = MultiAgent(env)
    model.run(10000)
    eps_run = 1000
    # 사용자 입력을 통해 훈련을 계속할지 결정합니다.
    while contn == "yes":
        model.run(eps_run)
        inp = input("continue training?")
        sp = inp.split(" ")
        contn = sp[0]
        if len(sp) > 1:
            eps_run = int(sp[1])

    # 모델을 평가할지 사용자에게 묻습니다.
    evlt = input("evaluate model?")
    if evlt == "yes":
        model.test(2000)
    model.env.graph.remove_nodes_from(nodes_to_remove)
    retrn = input("retrain?")
    while retrn == "yes":
        model.run(2000)
        retrn = input("retrain?")

    t1 = time.time()
    total = t1-t0
    print(f"Multi Agent {round(total/60, 2)} mins")

# GCN 알고리즘을 실행하는 함수
def gcn():
    num_nodes = 50
    max_neighbors = 50

    environment = Env("training_data/save_file",
                      num_nodes_in_graph=num_nodes, 
                      max_neighbors=max_neighbors,
                      graph = G )

    policy_net = GCN(num_nodes, max_neighbors).to(device)
    target_net = GCN(num_nodes, max_neighbors).to(device)

    gcn = GCN_Agent(
        outputs=num_nodes,
        policy_net=policy_net,
        target_net=target_net,
        num_nodes=num_nodes,
        env=environment
    )
    start_time = time()
    gcn.run(10_000)
    print(f'took {time()-start_time} (s)')

# SPF 알고리즘을 실행하는 함수
def spf():
    t0 = time.time()
    env = link_hop_env(directory + "/" + "spf_150" + ".csv",  G)
    env.graph = adjust_lat_band(env.graph, flows)
    env.graph.remove_nodes_from(nodes_to_remove)

    good = 0
    bad = 0
    reward = 0
    for _ in range(10000):
        obs, done = env.reset(), False
        path = nx.shortest_path(env.graph, obs[0], obs[1])
        for i in range(1, len(path)):
            action = env.neighbors.index(path[i])
            obs, reward, done, infos = env.step(action)
        if reward == 1.01 or reward == lwr:
            good += 1
        else:
            bad += 1
    t1 = time.time()
    total = t1-t0
    print(f"spf {round(total/60, 2)} mins")
    print(f"spf % Routed: {good / float(good + bad)}")

# ECMP 알고리즘을 실행하는 함수
def ecmp():
    t0 = time.time()
    env = link_hop_env(directory + "/" + "ecmp_150" + ".csv",    G)
    env.graph.remove_nodes_from(nodes_to_remove)

    good = 0
    bad = 0
    reward = 0
    for _ in range(10_000):
        obs, done = env.reset(), False
        paths = nx.all_shortest_paths(env.graph, obs[0], obs[1])
        path = []
        b = -1
        for p in paths:
            if compute_flow_value(env.graph, tuple(p)) > b:
                b = compute_flow_value(env.graph, tuple(p))
                path = p
        for i in range(1, len(path)):
            action = env.neighbors.index(path[i])
            obs, reward, done, infos = env.step(action)
        if reward == 1.01 or reward == lwr:
            good += 1
        else:
            bad += 1
    t1 = time.time()
    total = t1-t0
    print(f"ecmp {round(total/60, 2)} mins")
    print(f"ecmp % Routed: {good / float(good + bad)}")

# 주어진 네트워크 토폴로지에서 플로우를 생성하는 함수
def genrt_flows(num_flows):
    env = link_hop_env(directory + "/" + "flow_genrtr" + ".csv", G)
    flows = get_flows(env.graph, num_flows)
    return flows

# 네트워크 토폴로지와 플로우를 생성합니다.
G = create_graph(50,   100,   "50nodes.brite")
flows = genrt_flows(70)
nodes_to_remove = []

# 각 알고리즘을 실행합니다.
ma()
gcn()
ecmp()
spf()
  1. 라이브러리 및 모듈 임포트:
    • 필요한 라이브러리와 모듈을 임포트한다.이를 통해 그래프 연산, 강화학습, 그래프 컨볼루션 네트워크 등의 기능을 사용할 수 있다.
  2. 훈련 데이터 디렉토리 설정:
    • directory = "training_data": 훈련 데이터를 저장할 디렉토리의 이름을 설정다.
    • if not os.path.exists(directory): os.makedirs(directory): 해당 디렉토리가 없으면 새로 생성한다.
  3. Multi-Agent DQN 알고리즘 실행 함수 (ma):
    • ma 함수는 Multi-Agent DQN 알고리즘을 실행하는 함수이다.
    • 환경을 초기화하고, MultiAgent 모델을 생성한 후, 주어진 에피소드 수만큼 모델을 훈련한다.
    • 사용자 입력을 통해 추가 훈련을 진행하거나 모델을 평가할 수 있다.
  4. GCN 알고리즘 실행 함수 (gcn):
    • gcn 함수는 그래프 컨볼루션 네트워크 (GCN) 알고리즘을 실행하는 함수이다.
    • 환경을 초기화하고, GCN 모델을 생성한 후, 주어진 에피소드 수만큼 모델을 훈련한다.
  5. SPF 알고리즘 실행 함수 (spf):
    • spf 함수는 SPF (Shortest Path First) 알고리즘을 실행하는 함수이다.
    • 환경을 초기화하고, 주어진 횟수만큼 SPF 알고리즘을 사용하여 경로를 찾는다.
  6. ECMP 알고리즘 실행 함수 (ecmp):
    • ecmp 함수는 ECMP (Equal-Cost Multi-Path) 알고리즘을 실행하는 함수이다.
    • 환경을 초기화하고, 주어진 횟수만큼 ECMP 알고리즘을 사용하여 경로를 찾는다.
  7. 플로우 생성 함수 (genrt_flows):
    • genrt_flows 함수는 주어진 네트워크 토폴로지에서 플로우를 생성하는 함수이다.
    • 환경을 초기화하고, 주어진 수만큼의 플로우를 생성한다.
  8. 네트워크 토폴로지 및 플로우 생성:
    • 네트워크 토폴로지와 플로우를 생성한다.
  9. 알고리즘 실행:
    • ma(), gcn(), ecmp(), spf() 함수를 호출하여 각 알고리즘을 순차적으로 실행한다.

Train 결과

  1. 진행률:
    • 100%: 전체 훈련 에피소드 중 거의 100%가 완료
    • 9950/10000: 총 10,000 에피소드 중 9,950 에피소드가 완료
    • [49:11<00:09, 5.26it/s]: 지금까지 49분 11초가 소요되었으며, 예상 남은 시간은 9초이다. 현재 속도는 초당 5.26 에피소드이다.
  2. 100% 9950/10000 [49:11<00:09, 5.26it/s]
  3. 통계 정보:
    • latency_data: 네트워크의 지연 시간 데이터를 나타낸다.
    • 0.42670742113964470.39668232573582973: 지연 시간 데이터의 특정 통계 값 또는 메트릭 값을 나타낼 수 있다.
    • 9950: 현재 에피소드 번호
    • 48902: 누적된 스텝 수
    • tensor([1.0100]): 최근 에피소드에서 얻은 보상
  4. latency_data 0.4267074211396447 0.39668232573582973 9950 48902 tensor([1.0100])
  5. 훈련 중간 통계:
    • 이 부분은 훈련 중간에 수집된 데이터의 통계적 정보를 보여준다.
    • count: 데이터의 개수
    • mean: 평균값
    • 50%: 중앙값
    • 25%75%: 각각 1사분위수와 3사분위수
  6. count 182.000000 ... 50.000000 mean 0.044824 ... 1.025313 50% 0.044253 ... 1.227768 25% 0.039398 ... 1.061993 75% 0.050273 ... 1.315057
  7. 기타 정보:
    • decay: ε-greedy 정책에서 ε 값의 감소율
    • lr: 현재 학습률(learning rate)
  8. decay: 0.9120879120879121 lr: [2.1187083124088576e-09]
  9. 전체 훈련 시간:
    • 전체 훈련에 걸린 시간은 약 2961.83초
  10. took 2961.8257944583893 (s)
  11. ECMP 알고리즘 결과:
    • ECMP 알고리즘을 사용하여 테스트를 수행한 결과, 테스트 시간은 0.1분이며, 성공적으로 라우팅된 퍼센트는 100%
  12. ecmp 0.1 mins ecmp % Routed: 1.0
  13. SPF 알고리즘 결과:
    • SPF 알고리즘을 사용하여 테스트를 수행한 결과, 테스트 시간은 0.13분이며, 성공적으로 라우팅된 퍼센트는 100%
  14. spf 0.13 mins spf % Routed: 1.0

'GNN' 카테고리의 다른 글

미니넷(Mininet) 소개 및 사용법  (0) 2024.05.29
[Code] NGCF(Neural Graph Collaborative Filtering)  (0) 2023.08.19
LightGCN Preview  (0) 2023.08.19