DDPG算法代码详解
⽆⼈机辅助移动边缘计算的计算卸载优化:⼀种深度确定性策略梯度⽅法
贡献
考虑时隙⽆⼈机辅助MEC系统中时变信道状态,联合优化⽤户调度、⽆⼈机移动和资源分配,将⾮凸计算卸载问题制定为马尔科夫决策过程(MDP)问题,最⼩化初始时延。
考虑MDP模型,系统状态的复杂度⾮常⾼,计算卸载的决策需要⽀持连续动作空间,采⽤DDPG算法求解该问题,使⽤Actor⽹络做出动作,使⽤Critic⽹络近似动作价值函数Q给动作打分,获得最优策略。
DDPG框架
代码详解
手工兔子制作定义DDPG类,初始化,Session 是 Tensorflow 为了控制,和输出⽂件的执⾏的语句,运⾏ ssion.run() 可以获得你要得知的运算结果,或者是你所要运算的部分,后⾯会使⽤ ssion.run() 进⾏变量初始化操作。placeholder 是 Tensorflow 中的占位符,暂时储存变量,可以理解为⼀个空壳,传⼊值才进⾏计算,未传⼊则空壳不执⾏任何计算。
def__init__(lf, a_dim, s_dim, a_bound):
< = np.zeros((MEMORY_CAPACITY, s_dim *2+ a_dim +1), dtype=np.float32)# memory⾥存放当前和下⼀个state,动作和奖励
lf.pointer =0
lf.ss = tf.Session()
我有一个梦想英文lf.a_dim, lf.s_dim, lf.a_bound = a_dim, s_dim, a_bound,
lf.S = tf.placeholder(tf.float32,[None, s_dim],'s')# 输⼊
lf.S_ = tf.placeholder(tf.float32,[None, s_dim],'s_')
lf.R = tf.placeholder(tf.float32,[None,1],'r')招聘模板范本
tf.variable_scope 个⼈理解,主要是为了共享变量,取不同的名字就可以共享相同的变量了,DDPG⼀共是四个神经⽹络,Actor中两个神经⽹络的结构是相同的,Critic中两个神经⽹络的结构也是相同的,只是参数不同⽽已,分别写出⼀个神经⽹络的结构后,这些变量可以通过命名不同来实现共享。
下⾯的代码可以看出,Actor有两个⽹络,⼀个是主⽹络eval,⼀个是⽬标⽹络target,eval⽹络直接输出动作a,target⽹络输出动作a_,都是使⽤函数_build_a建⽴的,通过命名不同实现变量共享。同理Critic⽹络也是,分别是eval和target⽹络,输出是两个Q值,q,q_,从tensorboard可以看到actor和critic下分别是两个⽹络。下⾯进⼀步看如何建⽴actor⽹络和critic⽹络。trainable=True或者Fal主要是⽤来指定是否将神经⽹络中的变量添加到tensorboard图集中。
with tf.variable_scope('Actor'):对酒当歌人生几何譬如朝露去日苦多
lf.a = lf._build_a(lf.S, scope='eval', trainable=True)
所以美好
a_ = lf._build_a(lf.S_, scope='target', trainable=Fal)
with tf.variable_scope('Critic'):
# assign lf.a = a in memory when calculating q for td_error,
# otherwi the lf.a is from Actor when updating Actor
q = lf._build_c(lf.S, lf.a, scope='eval', trainable=True)
q_ = lf._build_c(lf.S_, a_, scope='target', trainable=Fal)
Actor
Actor⽹络主要输⼊状态s后,直接输出动作a。tf.layers.den( input, units=k )会在内部⾃动⽣成⼀个权矩阵kernel和偏移项bias,各变量具体尺⼨如下:对于尺⼨为[m, n]的⼆维张量input, tf.layers.den()会⽣成:尺⼨为[n, k]的权矩阵kernel,和尺⼨为[m, k]的偏移项bias。内部的计算过程为y = input * kernel + bias,输出值y的维度为[m, k]。
利⽤tensorflow封装的全连接层函数,输⼊状态,第⼀层神经元400(命名l1),第⼆层300(命名l2),第三层10(命名l3),输出层4(a_dim=4命名a)。actor的两个结构相同的⽹络就建好了,tensorboard如图所⽰。
def_build_a(lf, s, scope, trainable):
with tf.variable_scope(scope):
net = tf.layers.den(s,400, lu6, name='l1', trainable=trainable)
net = tf.layers.den(net,300, lu6, name='l2', trainable=trainable)
net = tf.layers.den(net,10, lu, name='l3', trainable=trainable)
a = tf.layers.den(net, lf.a_dim, anh, name='a', trainable=trainable)
return tf.multiply(a, lf.a_bound[1], name='scaled_a')
Critic踩踏天地
下⾯是Critic⽹络,对动作a进⾏打分,输出Q值。这⾥和上⾯建⽴神经⽹络的⽅式有⼀点不⼀样,因为Q函数需要输⼊状态s和动作a,所以s对应⼀个权重,a对应⼀个权重,整体还有⼀个偏置,然后经
过⼀个激活函数就相当于⼀层神经⽹络了,w1_s和w1_a和b1都是神经⽹络的参数,是需要保存并更新的,所以设置为trainable,这样输⼊到的第⼀层神经元为400,第⼆层为300(命名l2),第三层为10(命名为l3),输出为对动作的打分,标量。神经⽹络原理,线性求和后通过激活函数(⾮线性函数)。Critic的两个结构相同的⽹络就建好
了,tensorboard如图所⽰。
def_build_c(lf, s, a, scope, trainable):
with tf.variable_scope(scope):
n_l1 =400
w1_s = tf.get_variable('w1_s',[lf.s_dim, n_l1], trainable=trainable)
w1_a = tf.get_variable('w1_a',[lf.a_dim, n_l1], trainable=trainable)
b1 = tf.get_variable('b1',[1, n_l1], trainable=trainable)
net = lu6(tf.matmul(s, w1_s)+ tf.matmul(a, w1_a)+ b1)
net = tf.layers.den(net,300, lu6, name='l2', trainable=trainable)
net = tf.layers.den(net,10, lu, name='l3', trainable=trainable)
return tf.layers.den(net,1, trainable=trainable)# Q(s,a)
⾄此,四个神经⽹络结构就搭建好了。
神经⽹络重要的参数就是每层的权重和偏置,我们没有⽤⾮常原始的⽅式搭建神经⽹络,直接调⽤tf.layers.den进⾏搭建,每层具体的参数是不清楚的,但tensorflow提供了⾮常⽅便的tf.get_collection,从⼀个集合中取出全部变量,是⼀个列表,⼀共有四个⽹络,这样可以提取出四个⽹络的所有参数,⽤来进⾏更新。
# networks parameters
lf.ae_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Actor/eval')
lf.at_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Actor/target')
<_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Critic/eval')
<_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Critic/target')
经验回放池
由于神经⽹络输⼊时往往不是⼀个⼀个的输⼊,⽽是以⼩批量的形式输⼊,需要先收集⼀定的经验放
在经验回放池,每次⼩批量取出⽤来给神经⽹络进⾏训练,训练到⼀定次数停⽌训练。将s, a, r, s_称为⼀条经验,存放到经验池,直⾄达到最⼤容量。
def store_transition(lf, s, a, r, s_):
transition = np.hstack((s, a,[r], s_))
# transition = np.hstack((s, [a], [r], s_))
index = lf.pointer % MEMORY_CAPACITY # replace the old memory with new memory
<[index,:]= transition
lf.pointer +=1
神经⽹络参数更新
Actor和Critic中的两个主⽹络Actor_eval和Critic_eval分别通过TDerror和策略梯度进⾏更新。
平行检测计算TDerror,⽤来更新Critic_eval的⽹络参数,⽽Actor_eval的⽹络参数通过Q函数对actor_eval参数求导,这⾥实际上是Q对a求导然后对mu求导。{\theta^Q}
踮起脚就是这⾥的ce_params,⽽{\theta^\mu}是ae_params。q_target 对应y_i。