无人机辅助移动边缘计算的计算卸载优化:一种深度确定性策略梯度方法(6)——代码实现

无人机辅助移动边缘计算的计算卸载优化:一种深度确定性策略梯度方法(6)——代码实现

参考连接:

[1] Wang Y , Fang W , Ding Y , et al. Computation offloading optimization for UAV-assisted mobile edge computing: a deep deterministic policy gradient approach[J]. Wireless Networks, 2021:1-16.doi:https://doi.org/10.1007/s11276-021-02632-z

https://morvanzhou.github.io/tutorials/

https://github.com/fangvv/UAV-DDPG/blob/main/DDPG/DDPG_without_behavior_noise/ddpg_algo.py

https://blog.csdn.net/weixin_43835470/article/details/120881273

6 代码实现

本部分主要包括 Actor Critc,DDPG,DQN,Edge_only,Local_only 算法的基本实现思路,具体细节不予展示。

6.1 问题环境

问题环境主要包括了环境的各种状态 s 、无人机 uav 相关参数、用户 ue 相关参数和一些影响变量。其主要功能是模拟整个实验环境。主要动作包括了无人机飞行、无人机运算、用户移动和用户本地运算。

6.1.1 参数设计

参数包括了场地大小,无人机位置,带宽,噪声功率等参数,包括模拟实验中的所有参数。

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
#################### uav ####################
height = ground_length = ground_width = 100 # 场地长宽均为100m,UAV飞行高度也是
sum_task_size = 60 * 1048576 # 总计算任务60 Mbits
loc_uav = [50, 50] #无人机的初始位置

bandwidth_nums = 1
# 1MHz = 10^6Hz
B = bandwidth_nums * 10 ** 6 # 带宽1MHz
p_noisy_los = 10 ** (-13) # 噪声功率-100dBm ****
p_noisy_nlos = 10 ** (-11) # 噪声功率-80dBm ****
flight_speed = 50. # 飞行速度50m/s
f_ue = 6e8 # UE的计算频率0.6GHz
f_uav = 12e8 # UAV的计算频率1.2GHz
r = 10 ** (-27) # 芯片结构对cpu处理的影响因子
s = 1000 # 单位bit处理所需cpu圈数1000
p_uplink = 0.1 # 上行链路传输功率0.1W
# alpha0 = -30 # 距离为1m时的参考信道增益-30dB
alpha0 = 1e-5 # 距离为1m时的参考信道增益-50dB = 1e-5 ****
T = 200 # 周期200s
delta_t = 5 # 1s飞行, 后4s用于悬停计算
slot_num = int(T / delta_t) # 40个间隔
m_uav = 9.65 # uav质量/kg
e_battery_uav = 500000 # uav电池电量: 500kJ. ref: Mobile Edge Computing via a UAV-Mounted Cloudlet: Optimization of Bit Allocation and Path Planning

#################### ues ####################
M = 4 # UE数量
block_flag_list = np.random.randint(0, 2, M) # 4个ue,ue的遮挡情况
loc_ue_list = np.random.randint(0, 101, size=[M, 2]) # 位置信息:x在0-100随机
# task_list = np.random.randint(1048576, 2097153, M) # 随机计算任务1~2Mbits
task_list = np.random.randint(1572864, 2097153, M) # 随机计算任务1.5~2Mbits
# ue位置转移概率
# 0:位置不变; 1:x+1,y; 2:x,y+1; 3:x-1,y; 4:x,y-1
# 60%概率原地不动,10%概率向上下左右
loc_ue_trans_pro = np.array([[.6, .1, .1, .1, .1],
[.6, .1, .1, .1, .1],
[.6, .1, .1, .1, .1],
[.6, .1, .1, .1, .1]])

action_bound = [-1, 1] # 对应tahn激活函数
action_dim = 4 # 第一位表示服务的ue id;中间两位表示飞行角度和距离;后1位表示目前服务于UE的卸载率
state_dim = 4 + M * 4 # uav 剩余电量, uav 位置, 剩余总任务大小, 所有ue 位置, 所有ue 任务大小, 所有ue 遮挡情况

6.1.2 初始化部分

初始化包括 uav 剩余电量, uav 位置, 剩余总任务大小, 所有 ue 位置, 所有 ue 任务大小, 所有 ue 遮挡情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def __init__(self):
'''
初始化环境
包括uav 剩余电量, uav 位置, 剩余总任务大小, 所有ue 位置, 所有ue 任务大小, 所有ue 遮挡情况

Returns
-------
None.

'''
# uav battery remain, uav loc, remaining sum task size, all ue loc, all ue task size, all ue block_flag
self.start_state = np.append(self.e_battery_uav, self.loc_uav)
self.start_state = np.append(self.start_state, self.sum_task_size)
self.start_state = np.append(self.start_state, np.ravel(self.loc_ue_list))
self.start_state = np.append(self.start_state, self.task_list)
self.start_state = np.append(self.start_state, self.block_flag_list)
self.state = self.start_state

6.1.3 重置

由于实验是划分时间段进行的,涉及到每个步骤执行后的重置。

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
def reset(self):
'''
重置环境

Returns
-------
所有的环境信息

'''
self.reset_env()
# uav battery remain, uav loc, remaining sum task size, all ue loc, all ue task size, all ue block_flag
self.state = np.append(self.e_battery_uav, self.loc_uav)
self.state = np.append(self.state, self.sum_task_size)
self.state = np.append(self.state, np.ravel(self.loc_ue_list))
self.state = np.append(self.state, self.task_list)
self.state = np.append(self.state, self.block_flag_list)
return self._get_obs()

def reset_env(self):
'''
将所有的值设置为默认值

Returns
-------
None.
'''
self.sum_task_size = 100 * 1048576 # 总计算任务60 Mbits
self.e_battery_uav = 500000 # uav电池电量: 500kJ
self.loc_uav = [50, 50]
self.loc_ue_list = np.random.randint(0, 101, size=[self.M, 2]) # 位置信息:x在0-100随机
self.reset_step()

def reset_step(self):
'''
随机初始化ue 的计算任务和遮挡情况

Returns
-------
None.

'''
self.task_list = np.random.randint(2621440, 3145729, self.M) # 随机计算任务1.5~2Mbits -> 1.5~2 2~2.5 2.5~3 3~3.5 3.5~4
self.block_flag_list = np.random.randint(0, 2, self.M) # 4个ue,ue的遮挡情况

6.1.4 每段时间动作

在每个时间片段中进行的动作包括了选择用户,无人机飞行,计算任务,算出最大处理时延几个部分。

选择用户的时候可以随机选择用户,也可以类似DQN中根据对应的动作选择用户。

无人机飞行时需要计算飞行后的位置以及飞行时的能量消耗。

计算任务的时候需要考虑特殊情况,如计算任务已经完成,那么实验立刻终止,不进行后续步骤;最后一步的计算任务总量与我们规定的总任务量不一致,那么重置任务大小使其满足总计算任务量;无人机飞行时飞出场地,需要重新进行该步然后进行惩罚;以及无人机的电量不足以飞行或者计算,那么就将无人机所有电量都用完后,再进行下一片段。

计算最大处理时延后需要更新我们的奖惩,同时考虑用户移动。

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
def step(self):  # 0: 选择服务的ue编号 ; 1: 方向theta; 2: 距离d; 3: offloading ratio
step_redo = False #是否重做该步
is_terminal = False #是否终止
ue_id = np.random.randint(0, self.M) #随机选择一个用户

theta = 0 # 角度
offloading_ratio = 0 # ue卸载率
task_size = self.task_list[ue_id] #获取该用户的计算任务
block_flag = self.block_flag_list[ue_id] #获取该用户的遮挡情况

# 飞行距离
dis_fly = 0 # 1s飞行距离
# 飞行能耗
# delta_t:5s(1s飞行,4s计算) m_uav:uav质量
e_fly = (dis_fly / (self.delta_t * 0.5)) ** 2 * self.m_uav * (
self.delta_t * 0.5) * 0.5 # ref: Mobile Edge Computing via a UAV-Mounted Cloudlet: Optimization of Bit Allocation and Path Planning
# ref:通过无人机装载的云计算的移动边缘计算:位分配和路径规划的优化

# UAV飞行后的位置
dx_uav = dis_fly * math.cos(theta)
dy_uav = dis_fly * math.sin(theta)
loc_uav_after_fly_x = self.loc_uav[0] + dx_uav
loc_uav_after_fly_y = self.loc_uav[1] + dy_uav

# 服务器计算耗能
# f_uav:UAV的计算频率 s:单位bit处理所需cpu圈数
t_server = offloading_ratio * task_size / (self.f_uav / self.s) # 在UAV边缘服务器上计算时延
# r:芯片结构对cpu处理的影响因子
e_server = self.r * self.f_uav ** 3 * t_server # 在UAV边缘服务器上计算耗能

# 计算任务全部完成
if self.sum_task_size == 0:
is_terminal = True
# file_name = 'output.txt'
# with open(file_name, 'a') as file_obj:
# file_obj.write("\n======== This episode is done ========") # 本episode结束
reward = 0
# 最后一步计算任务和ue的计算任务不匹配
elif self.sum_task_size - self.task_list[ue_id] < 0:
# 将最后一步计算任务改成总计算任务的剩余量
self.task_list = np.ones(self.M) * self.sum_task_size
reward = 0
step_redo = True
# uav位置不对
elif loc_uav_after_fly_x < 0 or loc_uav_after_fly_x > self.ground_width \
or loc_uav_after_fly_y < 0 or loc_uav_after_fly_y > self.ground_length:
reward = -100
step_redo = True
# uav电量不能支持飞行
elif self.e_battery_uav < e_fly:
reward = -100
# uav电量不能支持计算
elif self.e_battery_uav - e_fly < e_server:
reward = -100
# 电量支持飞行,且计算任务合理,且计算任务能在剩余电量内计算
else:
delay = self.com_delay(self.loc_ue_list[ue_id], np.array([loc_uav_after_fly_x, loc_uav_after_fly_y]),
offloading_ratio, task_size, block_flag) # 计算delay
reward = delay #reward设置为时延
# 更新下一时刻状态
self.e_battery_uav = self.e_battery_uav - e_fly - e_server # uav 剩余电量
self.sum_task_size -= self.task_list[ue_id] # 剩余任务量
for i in range(self.M): # ue随机移动
tmp = np.random.rand()
if 0.6 < tmp <= 0.7:
self.loc_ue_list[i] += [0, 1]
elif 0.7 < tmp <= 0.8:
self.loc_ue_list[i] += [1, 0]
elif 0.8 < tmp <= 0.9:
self.loc_ue_list[i] += [0, -1]
elif 0.9 < tmp <= 1:
self.loc_ue_list[i] += [-1, 0]
else:
self.loc_ue_list[i] += [0, 0]
# np.clip是一个截取函数,用于截取数组中小于或者大于某值的部分,并使得被截取部分等于固定值。
# np.clip(a, a_min, a_max, out=None):
# a:输入矩阵;a_min:被限定的最小值,所有比a_min小的数都会强制变为a_min;
# a_max:被限定的最大值,所有比a_max大的数都会强制变为a_max;out:可以指定输出矩阵的对象,shape与a相同
# 限定了用户的位置
np.clip(self.loc_ue_list[i], 0, 100)
# self.task_list = np.random.randint(1048576, 2097153, self.M) # ue随机计算任务1~2Mbits
# 随机初始化ue 的计算任务和遮挡情况
self.reset_step()

return reward, is_terminal, step_redo

6.1.5 计算最大处理时延

根据用户位置,无人机位置,ue卸载率,ue的计算任务,ue的遮挡情况这些参数来计算出最大处理时延。

参照下列公式:

max{tlocal,k(i),tUAV,k(i)+ttr,k(i)}\max \left\{t_{l o c a l, k}(i), t_{U A V, k}(i)+t_{t r, k}(i)\right\}

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
def com_delay(self, loc_ue, loc_uav, offloading_ratio, task_size, block_flag):
'''
计算花费

Parameters
----------
loc_ue : 用户位置
loc_uav : 无人机位置
offloading_ratio : ue卸载率
task_size : ue的计算任务
block_flag : ue的遮挡情况

Returns
-------
时延

'''
# 获取uav与ue之间的距离
dx = loc_uav[0] - loc_ue[0]
dy = loc_uav[1] - loc_ue[1]
dh = self.height
dist_uav_ue = np.sqrt(dx * dx + dy * dy + dh * dh)

# 噪声功率
p_noise = self.p_noisy_los
if block_flag == 1:
p_noise = self.p_noisy_nlos
g_uav_ue = abs(self.alpha0 / dist_uav_ue ** 2) # 信道增益
trans_rate = self.B * math.log2(1 + self.p_uplink * g_uav_ue / p_noise) # 上行链路传输速率bps
t_tr = offloading_ratio * task_size / trans_rate # 上传时延,1B=8bit
t_edge_com = offloading_ratio * task_size / (self.f_uav / self.s) # 在UAV边缘服务器上计算时延
t_local_com = (1 - offloading_ratio) * task_size / (self.f_ue / self.s) # 本地计算时延
# 比较上传到服务器的时间和本地计算的时间,时延越长,返回的值越高
return max([t_tr + t_edge_com, t_local_com])

6.2 状态标准化

使用状态归一化算法对观测状态进行预处理,从而更有效地训练 DNN 。该算法将每个变量的最大值与最小值之差作为尺度因子。所提出的状态归一化算法可以很好地解决输入变量的大小差异问题。

在我们的工作中,变量 Ebattery (i),q(i),p1(i),,pK(i),Dremain (i),D1(i),,DK1(i)E_{\text {battery }}(i), \mathbf{q}(i), \mathbf{p}_{1}(i), \ldots, \mathbf{p}_{K}(i), D_{\text {remain }}(i), D_{1}(i), \ldots, D_{K-1}(i)DK1(i)D_{K-1}(i) 在状态集中处于不同的序列,这可能导致在训练中出现问题。如算法 1 所示,通过状态归一化对这些变量进行归一化,以防止出现这种问题。在状态归一化算法中,我们使用了五个尺度因子。每个因素可以解释如下。利用缩放因子 γb\gamma_b 来缩小无人机电池容量。由于 UAV 和 UE 具有相同的 x 和 y 坐标范围,我们使用 γx\gamma_xγy\gamma_y 分别缩小UAV和UE的x和y坐标。我们使用 γDrm\gamma_{D_{rm}} 来缩小整个时间段内剩余的任务,使用 γDUE\gamma_{D_{UE}} 来缩小时间段 i 内每个终端的任务大小。

2

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
import numpy as np
from UAV_env import UAVEnv

env = UAVEnv()
M = env.M


class StateNormalization(object):
'''
状态标准化类
'''
def __init__(self):
self.high_state = np.array(
[5e5, env.ground_length, env.ground_width, 100 * 1048576])
self.high_state = np.append(self.high_state, np.ones(M * 2) * env.ground_length)
self.high_state = np.append(self.high_state, np.ones(M) * 3145728)
self.high_state = np.append(self.high_state, np.ones(M))
self.low_state = np.zeros(20) # uav loc, ue loc, task size, block_flag
self.low_state[len(self.low_state) - 2 * M:len(self.low_state) - M] = np.ones(M) * 2621440


def state_normal(self, state):
state[len(state) - 2 * M: len(state) - M] -= 2621440
res = state / (self.high_state - self.low_state)
return res

6.3 强化学习类

这里使用自己想要的强化学习类来完成对应的策略选择。以DQN为例:

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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# Deep Q Network off-policy
class DeepQNetwork:

def __init__(
self,
n_actions,
n_features,
learning_rate=0.1,
reward_decay=0.001,
e_greedy=0.99,
replace_target_iter=200,
memory_size=MEMORY_CAPACITY,
batch_size=BATCH_SIZE,
# e_greedy_increment=8.684615e-05,
output_graph=False,
):
'''
初始化DQN网络

Parameters
----------
n_actions : TYPE
行为空间大小
n_features : TYPE
环境特征
learning_rate : TYPE, optional
学习率. The default is 0.1.
reward_decay : TYPE, optional
奖励衰减因子. The default is 0.001.
e_greedy : TYPE, optional
e贪心因子. The default is 0.99.
replace_target_iter : TYPE, optional
每多少次更新target参数. The default is 200.
memory_size : TYPE, optional
记忆库大小. The default is MEMORY_CAPACITY.
batch_size : TYPE, optional
批处理大小. The default is BATCH_SIZE.
# e_greedy_increment : TYPE, optional
e贪心因子增长幅度. The default is 8.684615e-05.
output_graph : TYPE, optional
是否输出图表. The default is False.

Returns
-------
None.

'''
self.n_actions = n_actions
self.n_features = n_features
self.lr = learning_rate
self.gamma = reward_decay
self.epsilon_max = e_greedy
self.replace_target_iter = replace_target_iter
self.memory_size = memory_size
self.batch_size = batch_size
# self.epsilon_increment = e_greedy_increment
# self.epsilon = 0 if e_greedy_increment is not None else self.epsilon_max
self.epsilon = 0.99

# total learning step
self.learn_step_counter = 0

# initialize zero memory [s, a, r, s_]
# 初始化记忆库
self.memory = np.zeros((MEMORY_CAPACITY, s_dim * 2 + 2), dtype=np.float32) # memory里存放当前和下一个state,动作和奖励

# consist of [target_net, evaluate_net]
# 构建神经网络
self._build_net()

# tf.get_collection():从一个集合中取出变量
# tf.GraphKeys 包含所有graph collection中的标准集合名
# tf.GraphKeys.GLOBAL_VARIABLES 则应该是所有的图变量的集合
t_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='target_net')
e_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='eval_net')

with tf.variable_scope('hard_replacement'):
self.target_replace_op = [tf.assign(t, e) for t, e in zip(t_params, e_params)]

self.sess = tf.Session()

if output_graph:
# $ tensorboard --logdir=logs
tf.summary.FileWriter("logs/", self.sess.graph)

# 全局变量初始化
self.sess.run(tf.global_variables_initializer())
self.cost_his = []


def _build_net(self):
'''
构建所有的网络图

Returns
-------
None.

'''
# ------------------ all inputs ------------------------
self.s = tf.placeholder(tf.float32, [None, self.n_features], name='s') # input State
self.s_ = tf.placeholder(tf.float32, [None, self.n_features], name='s_') # input Next State
self.r = tf.placeholder(tf.float32, [None, ], name='r') # input Reward
self.a = tf.placeholder(tf.int32, [None, ], name='a') # input Action

# 满足正态分布
w_initializer, b_initializer = tf.random_normal_initializer(0., 0.3), tf.constant_initializer(0.1)
# ------------------ build evaluate_net ------------------
with tf.variable_scope('eval_net'):
# tf.layers.dense():添加一个全连接层
# tf.nn.relu6:计算校正线性6:min(max(features, 0), 6)
e1 = tf.layers.dense(self.s, 100, tf.nn.relu6, kernel_initializer=w_initializer,
bias_initializer=b_initializer, name='e1')
# e2 = tf.layers.dense(e1, 48, tf.nn.relu6, kernel_initializer=w_initializer,
# bias_initializer=b_initializer, name='e2')
e3 = tf.layers.dense(e1, 20, tf.nn.relu, kernel_initializer=w_initializer,
bias_initializer=b_initializer, name='e3')
self.q_eval = tf.layers.dense(e3, self.n_actions, tf.nn.softmax, kernel_initializer=w_initializer,
bias_initializer=b_initializer, name='q')

# ------------------ build target_net ------------------
with tf.variable_scope('target_net'):
t1 = tf.layers.dense(self.s_, 100, tf.nn.relu6, kernel_initializer=w_initializer,
bias_initializer=b_initializer, name='t1')
# t2 = tf.layers.dense(t1, 48, tf.nn.relu6, kernel_initializer=w_initializer,
# bias_initializer=b_initializer, name='t2')
t3 = tf.layers.dense(t1, 20, tf.nn.relu, kernel_initializer=w_initializer,
bias_initializer=b_initializer, name='t3')
self.q_next = tf.layers.dense(t3, self.n_actions, tf.nn.softmax, kernel_initializer=w_initializer,
bias_initializer=b_initializer, name='t4')

with tf.variable_scope('q_target'):
q_target = self.r + self.gamma * tf.reduce_max(self.q_next, axis=1, name='Qmax_s_') # shape=(None, )
self.q_target = tf.stop_gradient(q_target)
with tf.variable_scope('q_eval'):
a_indices = tf.stack([tf.range(tf.shape(self.a)[0], dtype=tf.int32), self.a], axis=1)
self.q_eval_wrt_a = tf.gather_nd(params=self.q_eval, indices=a_indices) # shape=(None, )
with tf.variable_scope('loss'):
self.loss = tf.reduce_mean(tf.squared_difference(self.q_target, self.q_eval_wrt_a, name='TD_error'))
with tf.variable_scope('train'):
# self._train_op = tf.train.RMSPropOptimizer(self.lr).minimize(self.loss)
self._train_op = tf.train.AdamOptimizer(self.lr).minimize(self.loss)


def store_transition(self, s, a, r, s_):
'''
存储记忆元组

Parameters
----------
s : 当前状态
a : 动作
r : 奖惩
s_ : 下一状态

Returns
-------
None.

'''
if not hasattr(self, 'memory_counter'):
self.memory_counter = 0
# np.hstack将参数元组的元素数组按水平方向进行叠加
transition = np.hstack((s, a, [r], s_))
# replace the old memory with new memory
index = self.memory_counter % self.memory_size
self.memory[index, :] = transition
self.memory_counter += 1


def choose_action(self, observation):
'''
根据当前状态选择动作

Parameters
----------
observation : 对环境的观测

Returns
-------
action : 做出的动作

'''
# to have batch dimension when feed into tf placeholder
# 环境状态
observation = observation[np.newaxis, :]

# e贪心算法
if np.random.uniform() < self.epsilon:
# forward feed the observation and get q value for every actions
actions_value = self.sess.run(self.q_eval, feed_dict={self.s: observation})
action = np.argmax(actions_value)
else:
action = np.random.randint(0, self.n_actions)
return action


def learn(self):
'''
神经网络训练

Returns
-------
None.

'''
# check to replace target parameters
if self.learn_step_counter % self.replace_target_iter == 0:
self.sess.run(self.target_replace_op)
print('\ntarget_params_replaced\n')

# sample batch memory from all memory
# 从所有记忆中选取小批量记忆
if self.memory_counter > self.memory_size:
sample_index = np.random.choice(self.memory_size, size=self.batch_size)
else:
sample_index = np.random.choice(self.memory_counter, size=self.batch_size)
batch_memory = self.memory[sample_index, :]

_, cost = self.sess.run(
[self._train_op, self.loss],
feed_dict={
self.s: batch_memory[:, :self.n_features],
self.a: batch_memory[:, self.n_features],
self.r: batch_memory[:, self.n_features + 1],
self.s_: batch_memory[:, -self.n_features:],
})

self.cost_his.append(cost)

# increasing epsilon
# self.epsilon = self.epsilon + self.epsilon_increment if self.epsilon < self.epsilon_max else self.epsilon_max
self.learn_step_counter += 1

无人机辅助移动边缘计算的计算卸载优化:一种深度确定性策略梯度方法(6)——代码实现
https://fulequn.github.io/2022/01/Article202201211/
作者
Fulequn
发布于
2022年1月21日
许可协议