“No-Pain No-Gain: DRL Assisted Optimization in Energy-Constrained CR-NOMA Networks”代码分析和验证

本文详细解读了一篇2021年发表在IEEETransactionsonCommunications的论文,探讨了使用深度确定性强化学习(DDPG)在能源受限的多用户通信网络中进行优化的方法。研究者通过源代码分析和实验验证,比较了不同动作表示方式下DDPG的性能,发现使用能量平均值作为动作的DDPG算法表现更优,因为它避免了梯度问题和采样偏差。
摘要由CSDN通过智能技术生成

这篇paper于2021年发布在IEEE TRANSACTIONS ON COMMUNICATIONS 上,论文的具体细节可查看我的文章“No-Pain No-Gain: DRL Assisted Optimization in Energy-Constrained CR-NOMA Networks”论文学习笔记。作者已在GitHub上发布了源代码,下面将从源代码分析和添加实验验证两个方面展开介绍。

一、 源代码分析

作者设置了不同的PU个数、PU的坐标位置、PU和SU的信道状态等条件下的5个仿真实验,但我们只以其中最简单的一个实验为例来说明算法性能。

1. 基础参数设置

实验设定在二维平面上,具体参数设置如下:

  • BS位于坐标原点,SU U 0 U_0 U0位于(1m,1m)处,考虑2个PU,其中 U 1 U_1 U1 U 2 U_2 U2分别位于(0m,1m)和(0m,1000m)处;
  • 所有的信道只考虑大尺度路径衰减;
  • PU的发射功率 P n = 1 w P_n=1w Pn=1w,SU的最大发射功率为 P m a x = 0.1 w P_{max}=0.1w Pmax=0.1w,电池的最大容量为 E m a x = 0.1 J E_{max}=0.1J Emax=0.1J,每一帧持续时间为 T = 1 s T=1s T=1s
  • 总共有400个episode,每个episode包含100个step;每个episode开始时,SU的电池能量被初始化为 E m a x E_{max} Emax
  • 在每个step中会往buffer中存一条experience,并且会更新一次actor和critic network参数值。

2. DDPG网络设置

源代码中搭建DDPG网络的代码如下:

    def __init__(self, a_dim, s_dim, a_bound,):
        self.memory = np.zeros((MEMORY_CAPACITY, s_dim * 2 + a_dim + 1), dtype=np.float32)  
        self.pointer = 0
        self.sess = tf.Session() 

        self.a_dim, self.s_dim, self.a_bound = a_dim, s_dim, a_bound,
        self.S = tf.placeholder(tf.float32, [None, s_dim], 's')
        self.S_ = tf.placeholder(tf.float32, [None, s_dim], 's_')
        self.R = tf.placeholder(tf.float32, [None, 1], 'r')
        
        self.a = self._build_a(self.S,)  
        q = self._build_c(self.S, self.a, )  
        a_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Actor')  
        c_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Critic')
        ema = tf.train.ExponentialMovingAverage(decay=1 - TAU)  

        def ema_getter(getter, name, *args, **kwargs):
            return ema.average(getter(name, *args, **kwargs))

        target_update = [ema.apply(a_params), ema.apply(c_params)]    
        a_ = self._build_a(self.S_, reuse=True, custom_getter=ema_getter)  
        q_ = self._build_c(self.S_, a_, reuse=True, custom_getter=ema_getter) 

        a_loss = - tf.reduce_mean(q)  
        self.atrain = tf.train.AdamOptimizer(LR_A).minimize(a_loss, var_list=a_params) 

        with tf.control_dependencies(target_update):  
            q_target = self.R + GAMMA * q_  
            td_error = tf.losses.mean_squared_error(labels=q_target, predictions=q)  
            self.ctrain = tf.train.AdamOptimizer(LR_C).minimize(td_error, var_list=c_params)

        self.sess.run(tf.global_variables_initializer())  
        
    def _build_a(self, s, reuse=None, custom_getter=None):  
        trainable = True if reuse is None else False  
        with tf.variable_scope('Actor', reuse=reuse, custom_getter=custom_getter): 
            net = tf.layers.dense(s, 64, activation=tf.nn.relu, name='l1', trainable=trainable)  
            a2 = tf.layers.dense(net, 64, activation=tf.nn.tanh, name='l2', trainable=trainable)
            a = tf.layers.dense(a2, self.a_dim, activation=tf.nn.tanh, name='a', trainable=trainable)
            return tf.multiply(a, self.a_bound, name='scaled_a') 

    def _build_c(self, s, a, reuse=None, custom_getter=None):
        trainable = True if reuse is None else False
        with tf.variable_scope('Critic', reuse=reuse, custom_getter=custom_getter):
            n_l1 = 64
            w1_s = tf.get_variable('w1_s', [self.s_dim, n_l1], trainable=trainable) 
            w1_a = tf.get_variable('w1_a', [self.a_dim, n_l1], trainable=trainable)  
            b1 = tf.get_variable('b1', [1, n_l1], trainable=trainable)  
            net = tf.nn.relu(tf.matmul(s, w1_s) + tf.matmul(a, w1_a) + b1)  
            net2 = tf.layers.dense(net, 64, activation=tf.nn.relu, name='lx2', trainable=trainable)
            #not sure about this part
            return tf.layers.dense(net2, 1, trainable=trainable)  

DDPG本来应该包含4个网络,但在源代码中只搭建了2个网络_build_a和_build_c。这两个网络不属于4个网络中的任何一个,而是通过不同的参数设置和更新来轮流充当update network和target network的角色。具体解释如下:

  • actor network:_build_a方法中reuse=None(不复用),trainable=True(参数可更新),根据self.S计算出action值self.a (self.a = self._build_a(self.S,) )并取出要更新的网络参数( a_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=‘Actor’)),然后通过 critic network的输出q计算损失函数 a_loss( a_loss = - tf.reduce_mean(q)),最后更新网络参数a_params(self.atrain = tf.train.AdamOptimizer(LR_A).minimize(a_loss, var_list=a_params) )。因为a_params是直接取出的,所以这个参数更新结果最终会反馈到_build_a方法中各层的参数值上。
  • target actor network:_build_a方法中reuse=True(复用该网络结构),trainable=False(参数不更新),利用ema_getter方法(ema为指数移动平均,可对参数进行平滑更新,getter可对作用域中获取的网络参数添加自定义的处理逻辑ema,而不用重新搭建网络)对a_params进行软更新操作(计算图中操作,并不会影响网络参数值),然后根据self.S_计算出target action值a_ (a_ = self._build_a(self.S_, reuse=True, custom_getter=ema_getter))。
  • target critic network:_build_c方法中reuse=True(复用该网络结构),trainable=False(参数不更新),利用ema_getter方法对c_params进行软更新操作,然后根据a_,self.S_计算出target Q值q_(q_ = self._build_c(self.S_, a_, reuse=True, custom_getter=ema_getter) )。
  • critic network:_build_c方法中reuse=None(不复用),trainable=True(参数可更新),根据self.a,self.S计算出估计的Q值q(q = self._build_c(self.S, self.a, ))并取出要更新的网络参数(c_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope=‘Critic’)),然后根据q_和q计算损失函数td_error(q_target = self.R + GAMMA * q_; td_error = tf.losses.mean_squared_error(labels=q_target, predictions=q))并更新网络参数c_params(self.ctrain = tf.train.AdamOptimizer(LR_C).minimize(td_error, var_list=c_params))。

3. 实验理论结果

根据 U 0 U_0 U0 U 1 U_1 U1 U 2 U_2 U2之间的位置关系可知:

  • U 1 U_1 U1向BS发射数据时, U 1 U_1 U1会对 U 0 U_0 U0和BS之间的数据传输链路造成强干扰,所以 U 0 U_0 U0应该一直执行能量收集操作,即action=1,相应的 α n = 0 \alpha_n=0 αn=0 P 0 , n = 0 P_{0,n}=0 P0,n=0
  • U 2 U_2 U2向BS发射数据时,因为 U 2 U_2 U2 U 0 U_0 U0过于遥远,所以 U 0 U_0 U0无法从 U 2 U_2 U2处收集能量,但相应地 U 2 U_2 U2也不会对 U 0 U_0 U0和BS之间的传输链路造成干扰,所以此时 U 0 U_0 U0应该一直执行数据发射操作,即action=0,相应的 α n = 1 \alpha_n=1 αn=1 P 0 , n = 0.1 P_{0,n}=0.1 P0,n=0.1

二、添加实验验证

原文中设置了两个benchmark算法:benchmark 1为SU使用所有可用能量发射数据以后才开始收集能量,相应的时间分配因子 α n = m i n { 1 , E n / T P m a x } \alpha_n=min\{1,E_n/TP_{max}\} αn=min{1,En/TPmax};benchmark 2为SU的发射功率固定为 P m a x P_{max} Pmax,时间分配因子 α n \alpha_n αn在0和 m i n { 1 , E n / T P m a x } min\{1,E_n/TP_{max}\} min{1,En/TPmax}之间均匀分布。很明显,两个benchmark算法不涉及任何的优化和学习方法,并不能作为很好的对比算法。

原文中使用辅助变量 E ˉ n \bar{E}_n Eˉn作为DDPG的action,而其它Energy Harvesting的论文一般使用 α n \alpha_n αn P 0 , n P_{0,n} P0,n作为action(功率一般论文都会考虑,时间分配因子不一定),所以添加对比实验: α n \alpha_n αn P 0 , n P_{0,n} P0,n设为DDPG的action。原文隐晦表明 E ˉ n \bar{E}_n Eˉn作为action要比 α n \alpha_n αn P 0 , n P_{0,n} P0,n作为action性能要更好,但并没有相应的实验验证。这里做一个对比实验,除了观察两种算法的性能优劣以外,还可验证优化算法在强化学习中所起的作用。

添加实验验证所得仿真图如下所示:

Image

从图中可知, E ˉ n \bar{E}_n Eˉn作为action算法(DDPG_Enbar)的性能是优于 α n \alpha_n αn P 0 , n P_{0,n} P0,n作为action算法(DDPG_aP0n)的,具体分析如下:

  • α n \alpha_n αn P 0 , n P_{0,n} P0,n作为action时,正如原文所说,直接应用DDPG可能会存在训练不稳定的问题。当输出层选用tanh激活函数时,DDPG_aP0n算法会在训练初始或者中期出现action值为NaN的问题。这是因为tanh激活函数的输出范围为[-1,1],而两个action的取值范围分别在[0,1]和[0,0.1]之间。当利用replay buffer中的数据训练神经网络时,会迫使DDPG的输出层tanh输出[0,1]和[0,0.1]之间的值,而根据tanh激活函数图像可知,[0,0.1]之间值所对应的梯度很大,而[0,1]之间尤其是靠近1附近的值所对应的梯度很小,趋近于0,这会导致训练中梯度更新不一致,梯度爆炸或梯度消失的现象会使训练非常不稳定。除此以外,action取值范围差异也会导致采样偏差,即一些较大或者较小的action很少被采样到,从而使得网络无法学习到全局最优策略。当将输出层激活函数改为sigmoid时,采样偏差问题较为明显,action值基本上只能采到1和0.1,所以DDPG_aP0n算法性能肯定劣于DDPG_Enbar算法。
  • E ˉ n \bar{E}_n Eˉn作为action时,DDPG只有一个action,上面所说的问题全都不存在。DDPG_Enbar算法输出一个action值,再经过探索后得到新的action值,然后将其转换为 E ˉ n \bar{E}_n Eˉn值,最后根据优化算法求出的闭式解得到 α n \alpha_n αn P 0 , n P_{0,n} P0,n的值。优化算法先求 α n \alpha_n αn并且能保证 α n \alpha_n αn严格等于0或者1,然后再求 P 0 , n P_{0,n} P0,n得到0或者 − E ˉ n -\bar{E}_n Eˉn,这是能使reward最大的解决方案。但对于DDPG_aP0n算法而言,DDPG输出action值,再经过探索输出新的action值,然后直接将该值用于reward计算。此时 α n \alpha_n αn可能是0和1之间的值, P 0 , n P_{0,n} P0,n可能是0和 − E ˉ n -\bar{E}_n Eˉn之间的值,因为是随机探索而且并没有优化算法将它们修改成最理想的值,所以reward会小于DDPG_Enbar算法。

总的来说,当 E ˉ n \bar{E}_n Eˉn作为action时,DDPG更好训练,不会因为actions取值范围差异较大而出现梯度更新不一致、采样偏差等训练不稳定的问题。除此以外,DDPG_Enbar算法用优化算法消除了神经网络输出的随机性,即与reward有关的变量 α n \alpha_n αn P 0 , n P_{0,n} P0,n是通过优化算法求出的,不存在随机性且是能让reward最大的解决方案( α n = 0 / 1 \alpha_n=0/1 αn=0/1 P 0 , n = 0 / − E ˉ n P_{0,n}=0/-\bar{E}_n P0,n=0/Eˉn),神经网络输出随机的 E ˉ n \bar{E}_n Eˉn用来求 α n \alpha_n αn P 0 , n P_{0,n} P0,n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值