推荐文章DROO源码及论文学习
读论文《Deep Reinforcement Learning for Online Computation Offloading in Wireless Powered Mobile-Edge Computing Networks》的笔记
论文地址:用于无线移动边缘计算网络在线计算卸载的深度强化学习
论文代码地址:DROO源码
目录
一、Introduction
二、System Model
三、Local Computing Mode
四、Problem Formulation
五、THE DROO ALGORITHM
Algorithm Overview
保序量化的代码 :
之前的方法:KNN
Offloading Policy Update
Adaptive Setting of K
Convergence Performance
Impact of Updating Intervals Δ
Computation Rate Performance
一、Introduction
旨在解决无线供电的MEC网络中根据时变的无线信道条件优化地调整任务卸载和无线资源分配,需要快速求解困难的组合优化问题,传统数值优化方法难以实现。
采用binary卸载策略,即无线设备(WD)的每个计算任务要么在本地执行,要么完全卸载到MEC服务器。提出基于深度强化学习的在线卸载(DROO),将原始优化问题分解为卸载决策子问题和资源分配子问题,设计保序量化卸载动作生成,消除传统数值优化方法的复杂性,通过动态自适应程序进一步降低计算复杂性。
二、System Model
三、Local Computing Mode
四、Problem Formulation
五、THE DROO ALGORITHM
整体框架代码:
N = 10 #用户数量
n = 30000 # 时间帧数量
K = N # 初始化 K = N
decoder_mode = 'OP' # 量化模式,可以是 'OP' (Order-preserving) 或 'KNN'
Memory = 1024 # 内存结构的容量
Delta = 32 # 自适应 K 的更新间隔
print('#user = %d, #channel=%d, K=%d, decoder = %s, Memory = %d, Delta = %d'%(N,n,K,decoder_mode, Memory, Delta))
# 数据加载和处理
channel = sio.loadmat('./data/data_%d' %N)['input_h']#(30000, 10)->30000条N个信道增益
rate = sio.loadmat('./data/data_%d' %N)['output_obj'] # 这个速率只用于绘图,不用于训练 DROO
# 将信道值放大,以便更好地训练(这是深度学习中的常用技巧)
channel = channel * 1000000
# generate the train and test data sample index
# 将数据分为 80:20
# training data are randomly sampled with duplication if n > total data size
split_idx = int(.8 * len(channel))
num_test = min(len(channel) - split_idx, n - int(.8 * n)) # training data size
# 初始化DNN
mem = MemoryDNN(net = [N, 120, 80, N],
learning_rate = 0.01,
training_interval=10,
batch_size=128,
memory_size=Memory
)
rate_his = []
rate_his_ratio = []
mode_his = []
k_idx_his = []#索引
K_his = []
for i in range(n):
if i % (n//10) == 0:
print("%0.1f"%(i/n))#打印进度
if i> 0 and i % Delta == 0:
# index counts from 0
if Delta > 1:#每 Delta 个时间步更新 K
max_k = max(k_idx_his[-Delta:-1]) +1;#最近 Delta 个时间步内的最优K索引
else:
max_k = k_idx_his[-1] +1;
K = min(max_k +1, N)#K 不超过 N
if i < n - num_test:#训练阶段
# training
i_idx = i % split_idx# 训练数据索引
else:
#测试阶段
i_idx = i - n + num_test + split_idx# 测试数据索引
h = channel[i_idx,:]#选择当前时间步的信道数据 h
# the action selection must be either 'OP' or 'KNN'保序量化 K个卸载决策
m_list = mem.decode(h, K, decoder_mode)
# 每个卸载决策的总传输速率 r_list
r_list = []
for m in m_list:
r_list.append(bisection(h/1000000, m)[0])
#将最大传输速率的卸载决策存储在经验回放中
mem.encode(h, m_list[np.argmax(r_list)])
# the main code for DROO training ends here
# the following codes store some interested metrics for illustrations
# memorize the largest reward
rate_his.append(np.max(r_list))#最大传输速率
rate_his_ratio.append(rate_his[-1] / rate[i_idx][0])#最大传输速率与真实传输速率的比值
# record the index of largest reward
k_idx_his.append(np.argmax(r_list))#最大传输速率的对应的在K个卸载决策中的索引(排名)
# record K in case of adaptive K
K_his.append(K)#本次的K
mode_his.append(m_list[np.argmax(r_list)])#记录最大传输速率的卸载决策
Algorithm Overview
Offloading Action Generation
根据输入的无线信道增益 h 生成 k 个二元卸载决策 保序量化orKNN
def decode(self, h, k = 1, mode = 'OP'):
h = torch.Tensor(h[np.newaxis, :])#(10,)->torch.Size([1, 10])
self.model.eval()
m_pred = self.model(h)#先用DNN输出一个连续卸载决策
m_pred = m_pred.detach().numpy()
# 再用这个连续决策生成 k 个二元卸载决策
if mode is 'OP':#保序量化
return self.knm(m_pred[0], k)
elif mode is 'KNN':#KNN
return self.knn(m_pred[0], k)
else:
print("The action selection must be 'OP' or 'KNN'")
保序量化的代码 :
输入m:DNN网络输出的N个relaxed卸载动作(0-1之间连续)
如:[0.99010485 0.62969816 0.4329 0.4087384 0.7058292 0.4560974 0.49688646 0.452399 0.20186329 0.21191679]
shape为N:(10,)
def knm(self, m, k = 1):
# return k order-preserving binary actions
m_list = []
# generate the first binary offloading decision with respect to equation (8)
m_list.append(1*(m>0.5))#生成第一个二元卸载决策
if k > 1:
# generate the remaining K-1 binary offloading decisions with respect to equation (9)
m_abs = abs(m-0.5)#首先计算 m 中每个元素与 0.5 的绝对差值
idx_list = np.argsort(m_abs)[:k-1]#对绝对差值进行排序,并获取前 k-1 个最小差值的索引
for i in range(k-1):
if m[idx_list[i]] >0.5:
# set the \hat{x}_{t,(k-1)} to 0
m_list.append(1*(m - m[idx_list[i]] > 0))
else:
# set the \hat{x}_{t,(k-1)} to 1
m_list.append(1*(m - m[idx_list[i]] >= 0))
return m_list
输出m_list:K个保序量化后的动作
如:[array([1, 1, 0, 0, 1, 0, 0, 0, 0, 0]), array([1, 1, 0, 0, 1, 0, 1, 0, 0, 0]), array([1, 1, 0, 0, 1, 1, 1, 0, 0, 0]), array([1, 1, 0, 0, 1, 1, 1, 1, 0, 0]), array([1, 1, 1, 0, 1, 1, 1, 1, 0, 0]), array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0]), array([1, 0, 0, 0, 1, 0, 0, 0, 0, 0]), array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), array([1, 1, 1, 1, 1, 1, 1, 1, 0, 1]), array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])]
之前的方法:KNN
最近邻二元动作 knn 计算输入向量 m 与所有可能的二元卸载决策之间的距离,找与输入向量最相似的 k 个二元决策
def knn(self, m, k = 1):
# list all 2^N binary offloading actions
if len(self.enumerate_actions) is 0:
import itertools#笛卡尔积 所有可能的二元组合
self.enumerate_actions = np.array(list(map(list, itertools.product([0, 1], repeat=self.net[0]))))
# the 2-norm 计算与输入向量 m 的距离
sqd = ((self.enumerate_actions - m)**2).sum(1)#输入向量 m 与所有可能决策向量的欧氏距离的平方
idx = np.argsort(sqd)#距离最小的 k 个二元决策
return self.enumerate_actions[idx[:k]]
Offloading Policy Update
经验回放:使用存储的数据样本训练DNN
用Adam算法更新DNN的参数
收集足够数量的新数据样本后,每个时间步训练一次DNN
DNN迭代地从最佳状态动作对(𝐡𝑡,𝐱𝑡∗)中学习,随着时间的推移生成更好的卸载决策输出
在有限内存空间约束的情况下,DNN仅从最新(且更精细)的卸载策略生成的最新数据样本中学习
Adaptive Setting of K
Convergence Performance
Impact of Updating Intervals Δ
Computation Rate Performance
对于代码中optimization.py
方法是直接用的《Computation Rate Maximization for Wireless Powered Mobile-Edge Computing with Binary Computation Offloading》中提出的
包括先使用二分法找到最优的参数 v之后使用CD法优化模式选择,即固定其他通道的决策,仅改变当前通道的决策状态,对于每个通道,将其决策状态进行切换(0 变为 1,1 变为 0),计算相应的系统性能
论文地址具有二进制计算卸载的无线移动边缘计算的计算速率最大化,已标好代码中公式与论文中对应关系
# 二分搜索算法求解拉格朗日方程,先假定计算模式选择,然后优化传输时间分配
#线性搜索函数,需要两个输入,一个是信道矩阵,另一个是卸载动作,关于每个无线设备,除了W参数,其他的默认是同质的(我对代码的理解)。
def bisection(h, M, weights=[]):
# the bisection algorithm proposed by Suzhi BI
# average time to find the optimal: 0.012535839796066284 s
# parameters and equations
o=100
#是处理一位原始数据所需的周期数
p=3
#AP功率
u=0.7
#能量收集效率
eta1=((u*p)**(1.0/3))/o
#一个固定参数,不用理解
ki=10**-26
#能量效率系数,跟计算机能耗相关的
eta2=u*p/10**-10
B=2*10**6
#带宽
Vu=1.1
#Vu是原始数据(卸载数据)经过加密后的数据(原有数据在传输时进行额外添加)大小比原始数据的倍数
epsilon=B/(Vu*np.log(2))
x = [] # a =x[0], and tau_j = a[1:],时间分配矩阵
M0=np.where(M==0)[0]#本地
#为零或者1的索引
M1=np.where(M==1)[0]#卸载
hi=np.array([h[i] for i in M0])
#本地、卸载设备对应的信道
hj=np.array([h[i] for i in M1])
# h:信道信息数组,包含了每个通道的信道增益
if len(weights) == 0:
# default weights [1, 1.5, 1, 1.5, 1, 1.5, ...]
weights = [1.5 if i%2==1 else 1 for i in range(len(M))]
wi=np.array([weights[M0[i]] for i in range(len(M0))])
wj=np.array([weights[M1[i]] for i in range(len(M1))])
#w是每个WD的权重
def sum_rate(x):#总传输速率 式11a x第一项是a,后面是每个设备的tau
sum1=sum(wi*eta1*(hi/ki)**(1.0/3)*x[0]**(1.0/3))
sum2=0
for i in range(len(M1)):
sum2+=wj[i]*epsilon*x[i+1]*np.log(1+eta2*hj[i]**2*x[0]/x[i+1])
return sum1+sum2
def phi(v, j):#式17
return 1/(-1-1/(lambertw(-1/(np.exp( 1 + v/wj[j]/epsilon))).real))
def p1(v):#式18
p1 = 0
for j in range(len(M1)):
p1 += hj[j]**2 * phi(v, j)
return 1/(1 + p1 * eta2)
def Q(v):#二分法 找到最优的参数 v
sum1 = sum(wi*eta1*(hi/ki)**(1.0/3))*p1(v)**(-2/3)/3
#local计算
sum2 = 0
for j in range(len(M1)):
sum2 += wj[j]*hj[j]**2/(1 + 1/phi(v,j))
#计算卸载
return sum1 + sum2*epsilon*eta2 - v
#这里来自公式19
def tau(v, j):#式16
return eta2*hj[j]**2*p1(v)*phi(v,j)
# bisection starts here
# 找到一个参数 v,使得函数 Q(v) 的值等于 0
delta = 0.005 #二分法的精度
UB = 999999999#初始的上界
LB = 0#初始的下界
while UB - LB > delta:
v = (float(UB) + LB)/2
if Q(v) > 0:
LB = v
else:
UB = v
# 如果 Q(v) 的值大于 0,则将下界更新为当前的 v 值;否则,将上界更新为当前的 v 值
x.append(p1(v))#p1(v)是a x第一项
for j in range(len(M1)):
x.append(tau(v, j))
#计算每个WD的tau x后边是每个设备的tau
return sum_rate(x), x[0], x[1:]#总传输速率和时间分配向量 x 中的各个元素
#然后使用坐标下降Coordinate DescentCD法来优化模式选择
def cd_method(h):
N = len(h)#通道数量
M0 = np.random.randint(2,size = N)#初始通道状态
gain0,a,Tj= bisection(h,M0)#初始状态下的计算速率,a 和 Tj
g_list = []
M_list = []
while True:
# 固定其他通道的决策,仅改变当前通道的决策状态。
# 对于每个通道,将其决策状态进行切换(0 变为 1,1 变为 0),计算相应的系统性能。
for j in range(0,N):#对每一个通道 j 进行操作
M = np.copy(M0)
M[j] = (M[j]+1)%2#切换通道 j 的状态(0变为1,1变为0)
gain,a,Tj= bisection(h,M)#调整后的计算速率、时间分配
g_list.append(gain)
M_list.append(M)
g_max = max(g_list)
if g_max > gain0:#寻找最优解
gain0 = g_max
M0 = M_list[g_list.index(g_max)]#更新最卸载策略
else:
break
return gain0, M0