forked from WantEat-Mao/EdgeAISIM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Probabilistic_actor_critic_migration.py
187 lines (130 loc) · 6.5 KB
/
Probabilistic_actor_critic_migration.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
from edge_sim_py import *
import math
import os
import random
import msgpack
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from DDPG import DDPG
import torch
from torch.distributions import Categorical
def custom_collect_method(self) -> dict: # Custom collect method to measure the power consumption of each server
metrics = {
"Instance ID": self.id,
"Power Consumption": self.get_power_consumption(),
}
return metrics
global agent
global reward_list
global reward_count_list
global reward_count
reward_list = list()
power_list = list() # List to store total power consumption everytime the task scheduling algorithm is used
def my_algorithm(parameters):
print("\n\n")
total_reward = 0
total_power = 0 #We sum the power consumption after migrating each service
for service in Service.all(): #Iterate over every service
if not service.being_provisioned: #If service needs to be migrated
#Initialise our state vector, which is the concatenation of the cpu,memory,disk utilisation and current power consumption
state_vector = []
for edge_server in EdgeServer.all():
edge_server_cpu = edge_server.cpu
edge_server_memory = edge_server.memory
edge_server_disk = edge_server.disk
power = (edge_server_cpu * edge_server_memory * edge_server_disk) ** (1 / 3)
vector = [edge_server_cpu, edge_server_memory, edge_server_disk, power]
state_vector = state_vector + vector
#Pass the state vector to our actor network, and retrieve the action, as well as the action probabilities
state_vector = np.array(state_vector)
probs, action = agent.select_action(state_vector)
#print(action)
if EdgeServer.all()[action[0]] == service.server: #To conserve resources, we don't want to migrate back to our host
break
print(f"[STEP {parameters['current_step']}] Migrating {service} From {service.server} to {EdgeServer.all()[action[0]]}")
#Migrate service to new edgeserver
service.provision(target_server=EdgeServer.all()[action[0]])
#Get our next state, after taking action
next_state_vector = []
reward = 0
power = 0
for edge_server in EdgeServer.all():
edge_server_cpu = edge_server.cpu
edge_server_memory = edge_server.memory
edge_server_disk = edge_server.disk
power = (edge_server_cpu * edge_server_memory * edge_server_disk) ** (1 / 3)
vector = [edge_server_cpu, edge_server_memory, edge_server_disk, power]
next_state_vector = next_state_vector + vector
reward = reward + (1/edge_server.get_power_consumption()) #Our reward is the inverse of the edge server's power consumption
power = power + edge_server.get_power_consumption() #get the sum of powerconsumption of each edge server
next_state_vector = np.array(next_state_vector) #get our next state vector
agent.replay_buffer.push((state_vector, next_state_vector, probs, action, reward, np.float(0))) #add current episode into replay buffer
# agent.update(state_vector,action,next_state_vector,reward,False)
#print(reward)
total_reward += reward
total_power += power #Sum our power consumption
reward_list.append(total_reward)
power_list.append(total_power) #Append power consumption to power list for plotting
# agent.epsilon*=agent.epsilon_decay
agent.update()
def stopping_criterion(model: object):
# As EdgeSimPy will halt the simulation whenever this function returns True,
# its output will be a boolean expression that checks if the current time step is 600
return model.schedule.steps == 1000
simulator = Simulator(
tick_duration=1,
tick_unit="seconds",
stopping_criterion=stopping_criterion,
resource_management_algorithm=my_algorithm,
)
# Loading a sample dataset
simulator.initialize(input_file="sample_dataset1.json")
EdgeServer.collect = custom_collect_method
#Initialise of DQN agent with state and action dimension
#Here, state is the current cpu, memory and disk utilisation of the server, and action space is the choice of edge server
#i.e. the Edge server with the maximum Q- value will be migrated to
agent = DDPG(len(EdgeServer.all()) * 4, len(EdgeServer.all()))
# Executing the simulation
simulator.run_model()
#Retrieving logs dataframe for plot
logs = pd.DataFrame(simulator.agent_metrics["EdgeServer"])
print(logs)
df = logs
edge_server_ids = df['Instance ID'].unique()
# Determine the number of subplots based on the number of EdgeServers
num_subplots = len(edge_server_ids) + 1 # Add 1 for the rewards subplot
# Create subplots with the desired layout
fig, axes = plt.subplots(num_subplots, 1, figsize=(8, 4*num_subplots), sharex=True)
# Iterate over each EdgeServer and plot the data in the corresponding subplot
for i, edge_server_id in enumerate(edge_server_ids):
# Filter the data for the current EdgeServer
edge_server_data = df[df['Instance ID'] == edge_server_id]
# Extract the timestep and power consumption values
timesteps = edge_server_data['Time Step']
power_consumption = edge_server_data['Power Consumption']
# Plot the power consumption data for the current EdgeServer in the corresponding subplot
axes[i].plot(timesteps, power_consumption, label=f"EdgeServer {edge_server_id}")
# Set the subplot title and labels
axes[i].set_title(f"Power Consumption - EdgeServer {edge_server_id}")
axes[i].set_ylabel("Power Consumption")
axes[i].legend()
# Create a separate subplot for the rewards
# rewards_subplot = axes[-2]
# reward_count_list = list(range(1, len(reward_list) + 1))
# rewards_subplot.plot(reward_count_list, reward_list)
# rewards_subplot.set_title("Rewards")
# rewards_subplot.set_xlabel("Reward Count")
# rewards_subplot.set_ylabel("Reward")
power_subplot = axes[-1]
power_count_list = list(range(1, len(power_list) + 1))
power_subplot.plot(power_count_list, power_list)
power_subplot.set_title("Power Consumption")
power_subplot.set_xlabel("Power_step Count")
power_subplot.set_ylabel("Power")
# Adjust the spacing between subplots
plt.tight_layout()
plt.subplots_adjust(hspace=0.2)
# Display the plot
#plt.show()
plt.savefig('Probabilistic_actor_critic_migration_power_consumption_final_uncropped.png')