Skip to content

Commit

Permalink
Update some code. Add a plot of "delay stress level" and "rwd vs CDF …
Browse files Browse the repository at this point in the history
…accept request"
  • Loading branch information
JosephThinhTran committed Nov 30, 2021
1 parent 1ed3071 commit 72b006d
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 45 deletions.
16 changes: 12 additions & 4 deletions AC_SFC_Main_01.05.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
import shutil
import argparse
from dataset_and_params import get_sfc_spec_file, get_train_datasets, get_test_datasets, get_train_test_params
from plot_results import plot_episode_rwd, plot_loss_val, plot_accum_accept_req, plot_throughputs, plot_rsc_usages
from plot_results import plot_episode_rwd, plot_loss_val, plot_accum_accept_req
from plot_results import plot_throughputs, plot_rsc_usages, plot_delay_stress_level


# def read_reward_data(log_file):
Expand Down Expand Up @@ -432,6 +433,10 @@ def main(args):
''' Plot resource usages over epochs'''
plot_rsc_usages(args.mode, input_params, now)

''' Plot delay stress level'''
plot_delay_stress_level(args.mode, input_params, now)


#######################################################

print("Return the Before_Train and After_Train models")
Expand Down Expand Up @@ -529,12 +534,15 @@ def calc_model_diff(before_model, after_model, net_arch):
parser.add_argument("--opt_centered", default=False, type=bool, help="Whether using centered or not for the optimzer")
parser.add_argument("--test_size", default="15k", type=str,
help="Choose 15k-dataset or 100k-dataset for testing. Support options: 15k, 100k")

parser.add_argument("--traffic_type", default='Legacy', type=str,
help="Traffic type. Support options: 'Legacy', 'Conus36'")
parser.add_argument("--en_log", default=False, type=bool, help="Enable training/testing log. Options: True/False")

args = parser.parse_args()
if args.n_workers <= 0:
raise ValueError("A positive value is required.")
if args.n_workers > 12:
raise ValueError("Support upto 12 workers.")
if args.n_workers > 24:
raise ValueError("Support upto 24 workers.")

if args.mode == "test_mode":
args.n_workers = 1
Expand Down
36 changes: 30 additions & 6 deletions actor_critic_models_SFC_v05.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,15 @@ def __init__(self, worker_id, global_model, optimizer, params, traffic_file, cou
self.throughput_log = os.path.join(params['train_dir'], 'W_' + str(self.worker_id) + "_throughputs.log")
self.rsc_usage_log = os.path.join(params['train_dir'], 'W_' + str(self.worker_id) + "_rsc_usage.log")
self.registerd_req_log = os.path.join(params['train_dir'], 'W_' + str(self.worker_id) + "_registerd_req.log")
self.delay_stress_log = os.path.join(params['train_dir'], 'W_' + str(self.worker_id) + "_delay_stress.log")
else:
self.operation_log = os.path.join(params['test_dir'], "W_" + str(self.worker_id) + "_test.log")
self.ep_reward_log = os.path.join(params['test_dir'], "W_" + str(self.worker_id) + "_ep_reward.log")
self.accept_ratio_log = os.path.join(params['test_dir'], 'W_' + str(self.worker_id) + "_test_accept_ratio.log")
self.throughput_log = os.path.join(params['test_dir'], 'W_' + str(self.worker_id) + "_test_throughputs.log")
self.rsc_usage_log = os.path.join(params['test_dir'], 'W_' + str(self.worker_id) + "_test_rsc_usage.log")
self.registerd_req_log = os.path.join(params['test_dir'], 'W_' + str(self.worker_id) + "_test_registerd_req.log")
self.delay_stress_log = os.path.join(params['test_dir'], 'W_' + str(self.worker_id) + "_test_delay_stress.log")
print(f'Successful Init A3C_Worker {self.worker_id}')

"""""""""""""""""""""""""""""""""""""""""""""""""""""""'"""
Expand Down Expand Up @@ -447,6 +449,7 @@ def run(self):
self.calc_throughputs()
self.export_resource_usage()
self.export_registered_reqs()
self.export_delay_stress_level()
gc.collect()

''''''''''''''''''''''''''''''''''''''''''''''''
Expand All @@ -468,10 +471,11 @@ def run_episode(self, epoch):
print(f"Req_Id={req['id']}| source={req['source']}| destination={req['destination']}|\
{req['sfc_id']}:[{self.edf.sfc_specs[req['sfc_id']]}]|\
bw={req['bw']} delay_req={req['delay_req']:.4f}")
with open(self.operation_log, 'a') as fp:
print(f"Req_Id={req['id']}| source={req['source']}| destination={req['destination']}|\
{req['sfc_id']}:[{self.edf.sfc_specs[req['sfc_id']]}]|\
bw={req['bw']} delay_req={req['delay_req']:.4f}", file=fp)
if self.params['en_log']:
with open(self.operation_log, 'a') as fp:
print(f"Req_Id={req['id']}| source={req['source']}| destination={req['destination']}|\
{req['sfc_id']}:[{self.edf.sfc_specs[req['sfc_id']]}]|\
bw={req['bw']} delay_req={req['delay_req']:.4f}", file=fp)

#### Check new time slot
if req['arrival_time'] == self.cur_time_slot + 1 + self.start_time_slot:
Expand Down Expand Up @@ -657,8 +661,9 @@ def run_episode(self, epoch):
success_embed = 1 if done_embed > 0 else 0

print(f"Time_{self.cur_time_slot}_Epoch_{epoch}_Step_{mov} Cur_node={prev_node_id} {req['sfc_id']}-{prev_hol_vnf_name} Action={action} Residual_delay={residual_delay:.4f} Step_Reward={reward:.3f} Success_embed={success_embed}")
with open(self.operation_log, 'a') as train_fp:
print(f"Time_{self.cur_time_slot}_Epoch_{epoch}_Step_{mov} Cur_node={prev_node_id} {req['sfc_id']}-{prev_hol_vnf_name} Action={action} Residual_delay={residual_delay:.4f} Step_Reward={reward:.3f} Success_embed={success_embed}", file=train_fp)
if self.params['en_log']:
with open(self.operation_log, 'a') as train_fp:
print(f"Time_{self.cur_time_slot}_Epoch_{epoch}_Step_{mov} Cur_node={prev_node_id} {req['sfc_id']}-{prev_hol_vnf_name} Action={action} Residual_delay={residual_delay:.4f} Step_Reward={reward:.3f} Success_embed={success_embed}", file=train_fp)

# Register the NEWLY successul embedded request to the serving list
if success_embed > 0:
Expand Down Expand Up @@ -1089,6 +1094,25 @@ def calc_avg_path_len(self):
tot_links += len(n_diff_nodes) - 1
avg_path_len = tot_links / self.n_accepted_req
return avg_path_len

def export_delay_stress_level(self):
"""Export delay stress level [%] of accepted requests into file
Plot a histogram of the delay stress level
"""
with open(self.delay_stress_log, 'w') as fp:
for i in range(len(self.delay_rate_hist)):
print(f"{self.delay_rate_hist[i]*100}", file=fp)

# x = np.array(self.delay_rate_hist) * 100
# plt.figure(figsize=(10, 7.5))
# plt.xlabel("Delay stress level [%]", fontsize=22)
# plt.ylabel("Num. of requests", fontsize=22)
# plt.hist(x, bins=10)
# if self.is_train:
# fig_name = os.path.join(self.params['train_dir'], 'W_' + str(self.worker_id) + "_delay_stress")
# else:
# fig_name = os.path.join(self.params['test_dir'], 'W_' + str(self.worker_id) + "_test_delay_stress")
# plt.savefig(fig_name)

# END OF A3CWORKER CLASS=============================================================================

Expand Down
72 changes: 37 additions & 35 deletions dataset_and_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,40 +110,42 @@ def get_train_test_params(max_epochs, sfc_spec_file,
ADV_STYLE = {'n_step_return': 1, 'gae': 2}# n-step return or GAE

params = {'epochs': max_epochs,
'n_workers': args.n_workers,
'sfc_spec': sfc_spec_file,
'datasets': train_dataset_list,
'data_folder': args.data_folder,
'model_dir': args.model_dir,
'train_dir': train_dir,
'test_dir': test_dir,
'train_freq': args.train_freq,
'adv_style': ADV_STYLE[args.adv_style],
'hidden_layers': fc_hidden_layers,
'input_dims': state_dim,
'actor_dims': actor_ouput_dim,
'learning_rate': args.lr,
'gamma': args.gamma,
'tau': args.tau,
'critic_factor': args.critic_factor,
'actor_factor': args.actor_factor,
'entropy_factor': args.entropy_factor,
'entropy_decay_val': args.entropy_decay_val,
'entropy_decay_freq': args.entropy_decay_freq,
'entropy_min': args.entropy_min,
'betas': args.betas,
'big_rwd': args.big_rwd,
'N_steps': args.n_steps,
'max_moves': args.max_moves,
'resource_scaler': args.rsc_scaler,
'is_binary_state': args.is_binary_state,
'state_noise_scale': args.state_noise_scale,
'opt_lr': args.opt_lr,
'opt_epsilon': args.opt_epsilon,
'opt_weight_decay': args.opt_weight_decay,
'opt_alpha': args.opt_alpha,
'opt_momentum': args.opt_momentum,
'opt_centered': args.opt_centered
}
'n_workers': args.n_workers,
'sfc_spec': sfc_spec_file,
'datasets': train_dataset_list,
'traffic_type': args.traffic_type,
'data_folder': args.data_folder,
'model_dir': args.model_dir,
'train_dir': train_dir,
'test_dir': test_dir,
'train_freq': args.train_freq,
'adv_style': ADV_STYLE[args.adv_style],
'hidden_layers': fc_hidden_layers,
'input_dims': state_dim,
'actor_dims': actor_ouput_dim,
'learning_rate': args.lr,
'gamma': args.gamma,
'tau': args.tau,
'critic_factor': args.critic_factor,
'actor_factor': args.actor_factor,
'entropy_factor': args.entropy_factor,
'entropy_decay_val': args.entropy_decay_val,
'entropy_decay_freq': args.entropy_decay_freq,
'entropy_min': args.entropy_min,
'betas': args.betas,
'big_rwd': args.big_rwd,
'N_steps': args.n_steps,
'max_moves': args.max_moves,
'resource_scaler': args.rsc_scaler,
'is_binary_state': args.is_binary_state,
'state_noise_scale': args.state_noise_scale,
'opt_lr': args.opt_lr,
'opt_epsilon': args.opt_epsilon,
'opt_weight_decay': args.opt_weight_decay,
'opt_alpha': args.opt_alpha,
'opt_momentum': args.opt_momentum,
'opt_centered': args.opt_centered,
'en_log': args.en_log
}

return params
40 changes: 40 additions & 0 deletions plot_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,43 @@ def plot_rsc_usages(mode, params, time):
plt.savefig(fig_name)

return rsc_usage_data

def read_delay_stress_data(log_files):
datas = []
for fname in log_files:
x = []
with open(fname, 'r') as f:
lines = f.readlines()
for i in range(len(lines)):
x.append(float(lines[i].split()[0]))
datas.append(x)
return datas

def plot_delay_stress_level(mode, params, time):
OPERATION_MODE = {'train_mode': 1, 'test_mode': 0}

delay_files = []
for w in range(params['n_workers']):
if OPERATION_MODE[mode] == OPERATION_MODE["train_mode"]:
fp = os.path.join(params['train_dir'], 'W_' + str(w) + "_delay_stress.log")
else:
fp = os.path.join(params['test_dir'], 'W_' + str(w) + "_test_delay_stress.log")
delay_files.append(fp)
delay_datas = read_delay_stress_data(delay_files)

for i in range(params['n_workers']):
x = delay_datas[i]
plt.figure(figsize=(10, 7.5))
plt.xlabel("Delay stress level [%]", fontsize=22)
plt.ylabel("Num. of requests", fontsize=22)
plt.hist(x, bins=10)
if OPERATION_MODE[mode] == OPERATION_MODE["train_mode"]:
fig_name = os.path.join(params['train_dir'],
'W_' + str(i) + "_delay_stress_" + time.strftime("%Y-%B-%d__%H-%M"))
else:
fig_name = os.path.join(params['test_dir'],
'W_' + str(i) + "_test_delay_stress_" + time.strftime("%Y-%B-%d__%H-%M"))
plt.savefig(fig_name)



97 changes: 97 additions & 0 deletions rwd_and_cdf_accept_req.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
"""
Created on Sat Nov 27 23:38:22 2021
@author: Onlyrich-Ryzen
Plot the (moving average) reward and CDF of accepted requests
over the training episodes
"""

import numpy as np
import matplotlib.pyplot as plt
import os
import data_utils
from datetime import datetime
from pathlib import Path
import argparse

#### Plot the reward and accumulated accepted request in a same figure
# N_EPOCHS = 10
# x = np.linspace(0, N_EPOCHS, 11)
# moving_avg_reward = np.linspace(10,20, 11)
# cdf_accum = np.linspace(10_000, 0, 11)


# # reward curve
# plt.figure(figsize=(10,7.5))
# fig, ax = plt.subplots()
# ax.plot(moving_avg_reward, color='red', linestyle='-')
# ax.set_xlabel("Episodes", fontsize=20)
# ax.set_ylabel("Reward", fontsize=20)


# # accum accepted request curve
# ax2 = ax.twinx()
# ax2.plot(cdf_accum, color='blue', linestyle = '-.')
# ax2.set_ylabel("Num. of Requests", fontsize=18)
# plt.grid(axis='both')


def main():
now = datetime.now()
# RESULT_DIR = args.result_dir
# NTimeSlots = args.n_time_slots
RESULT_DIR = "results_comparison_2021_Nov_29"
NTimeSlots = 200_000


# Read the A3C Accepted request log
A3cAccReqFile = os.path.join(RESULT_DIR, 'W_0_accept_ratio.log')
with open(A3cAccReqFile, 'r') as fp:
A3cAccReqLines = fp.readlines()

A3cCdfAcc = []
TotAccReq = 0
for i in range(len(A3cAccReqLines) - 5):
TotAccReq += float(A3cAccReqLines[i].split()[0])
A3cCdfAcc.append(TotAccReq)

# Read the A3C Episode reward log
A3cRwdFile = os.path.join(RESULT_DIR, 'W_0_ep_reward.log')
with open(A3cRwdFile, 'r') as fp:
A3cRwdLines = fp.readlines()
A3cRwdEps = [float(A3cRwdLines[i].split()[0]) for i in range(NTimeSlots)]
A3cMovRwd = data_utils.mov_window_avg(A3cRwdEps, 1000)

# px = 1/plt.rcParams['figure.dpi'] # pixel in inches
dpi = 100
# Plot results
plt.figure(figsize=(1500/dpi, 1000/dpi), dpi=dpi)
fig, ax = plt.subplots()
ax.plot(A3cMovRwd, color='red', linestyle='-')
ax.set_xlabel("Episodes", fontsize=22)
ax.set_ylabel("Reward", fontsize=22, color='red')

ax2 = ax.twinx()
ax2.plot(A3cCdfAcc, color='blue', linestyle = '-.')
ax2.set_ylabel("Num. of Requests", fontsize=22, color='blue')
# plt.grid(axis='both')
fig_name = os.path.join(RESULT_DIR, "A3C_Rwd_CDF_Accept_Req_" + now.strftime("%Y-%B-%d__%H-%M"))
plt.savefig(fig_name, dpi=dpi)

# #### Run the script
# if __name__ == "__main__":
# parser = argparse.ArgumentParser(description="Plot Reward and CDF Accepted Requests in the same figure")
# parser.add_argument("result_dir", type=str, help="Folder storing the results")
# parser.add_argument("--n_time_slots", default=200_000, type=int,
# help="Number of time slots in the training")
# # parser.add_argument("--start_time", default=0, type=int, help="Starting time slot for throughput calculation")
# args = parser.parse_args()

# main(args)
# print('Done!')

if __name__ == "__main__":
main()
print("Done!")

0 comments on commit 72b006d

Please sign in to comment.