两种深度强化学习算法在⽹络调度上的应⽤与优化(DQNA3C )对我来说英语
⾸先给出论⽂地址和代码,
从题⽬可以得知, 这是⼀篇有关强化学习的论⽂, 具体的⼯作是⽤A3C算法来优化10个nsor的AOI以及保证URLLC,所谓URLLC,即给每⼀个nsor都设定⼀个阈值,接着通过训练来保证每⼀个nsor的AOI不超过这个阈值,否则就会受到惩罚,给⼀个很负的奖励,通俗的来讲就是保证可靠性,这是优化⽬标。状态的设置是10个nsor的AOI和最后5个包的下载时间和吞吐量,将这些状态送往神经⽹络最后整合⼀下, 再通过⼀个全连接神经⽹络得到10个概率分布, 作者选择动作的⽅式和⼀般A3C选择动作的⽅式些许不同,但影响不⼤,感兴趣的可以在代码⾥⾯查看,⾥⾯涉及到了很多知识, 模型的保存、交叉熵、tensorboard的可视化,模型的保存⽤于Test并给出最后的结果,也就是论⽂中的表格数据和图,Train⽂件夹是⽤来训练模型的,以上是作者所⽤的A3C算法,尽管这个模型还有很多的不⾜,但是很简单,作为学习⼊门是可以的了。
另外,我⽤最基本的DQN也实现了⼀下这篇论⽂, 最后的结果如下:
结果不⽐A3C差,我写的代码有时间也会上传到GitHub,以上。
包括了train和模型保存两个重要的部分,算法基本的流程和⼤家所学的相差不⼤, 不过由于记忆池的变化,所以有稍许的改动,原作者的模型保存是使⽤了⼀个队列来传递梯度下降的值到另⼀个函数⾥⾯去, 虽然最后我搞明⽩了所谓队列在两个函数之间传输的特点,但是⽤在我的代码⾥⾯就是⼀直⽆法收敛,所以我索性放到了train⾥⾯。
1.DQN 算法核⼼−learn
def prepare_learn(lf, done):
# check to replace target parameters ⽤eval ⽹络替换tartget ⽹络的参数,
if lf.learn_step_counter % lf.replace_target_iter == 0:
lf.ss.place_target_op)
print('\ntarget_params_replaced\n')
# sample batch memory from all memory
_counter > lf.memory_size:
sample_index = np.random._size, size=lf.batch_size)
el: # 如果计数累加不超过记忆池,从⽬前的memory_counter 中选32个索引值
sample_index = np.random._counter, size=lf.batch_size)性格不合
batch_memory = lf.memory[sample_index, :] # 根据索引取memory 中的数据 ,数据量是随机的不相关的数据
# batch_memory 中都是状态,这些状态包含了next_state ,
q_eval = lf.predict_eval(batch_memory[:, :, 0:lf.s_dim[1]])
q_next = lf.predict_next(batch_memory[:, :, lf.s_dim[1]: lf.s_dim[0] - 2])
q_target = py()
batch_index = np.arange(lf.batch_size, dtype=np.int32)
action_vec = batch_memory[:, :, 11]
reward_vec = batch_memory[:, :, 10]
action_index = []
# 数据是记忆库的数据
reward = []
for a in action_vec:
i = np.argmax(a)
action_index.append(i)
# print(action_index)
for r in reward_vec:
i = r[0]
reward.append(i)
lf.Reward_his.append(i)
# 32个索引值, 原来源是memory 中的act 数据,
eval_act_index = action_index
# ⽆法得到未来的期望
if done:
q_target[batch_index, eval_act_index] = reward
el:
q_target[batch_index, eval_act_index] = reward + lf.gamma * np.max(q_next, axis=1)
lf.epsilon = lf.epsilon + lf.e_greedy_increment if lf.epsilon < lf.epsilon_max el lf.epsilon_max
lf.learn_step_counter += 1
_, cost = lf.ss.run([lf._train_op, lf.loss],
feed_dict={
lf.q_target: q_target,
lf.inputs_e: batch_memory[:, :, 0:lf.s_dim[1]],
})
if lf.learn_step_counter % 100 == 0:
lf.saver.save(lf.ss, SUMMARY_DIR + "/nn_model_ep_" + str(lf.learn_step_counter) + ".ckpt")
print(f"MODEL READY_{lf.learn_step_counter}!)")
另外在训练过程中的可视化也极为重要, 因为代码⼀开始是肯定⽆法收敛的,除⾮你是天选之⼦,如上代码的收敛是在不断测试下有的,甚⾄让笔者⼀度怀疑这算法到底可不可⾏。
可视化有多种⽅法,可以是⼀个特定数据反映数据是否收敛, 更好的当然是最为直接的图了,我在写代码的过程中发现如果选择每⼀个nsor的概率接近10%,即平均的更新每⼀个nsor,这样对应到奖励值上也会有⼀个不太差的结果, 但是在中, 我发现选择频率最⾼的nsor接近收敛与19% , 这和是有⼀些不同的,它的概率通过输出就是稳定在10%左右, 这⾥体现了算法的差异性。这是⼀⽅⾯, 另⼀⽅⾯是在训练过程中,不同的算法选择更新nsor的临界点不同,这是上⾯所说的概率的另⼀个更加具体的体现,即的阈值为,那么会选择在它的达到19时就更新它,不让它继续增加下去了,这和算法本⾝的训练过程有关,优化⽬标既然是最⼩化所有, 那么这个算法就认为在19更新它的我可
以获得最⼤的奖励, 但对于肯定是不⼀样了, 具体的数据我没有论证, ⼤家如果感兴趣可以统计⼀下每⼀个算法在哪⼀个数值更新它的, 对⽐⼀下两个算法的不同.
DQN A 3C softmax nsor 130DQN AOI SensorAOI AOI A 3C AOI土豆土豆
def build_eval_net(lf):
with tf.variable_scope('eval_net', ):
# 这个inputs 理应是s
inputs = tflearn.input_data(shape=[None, lf.s_dim[0], lf.s_dim[1]])
split_0 = tflearn.fully_connected(inputs[:, 0:1, -1], Neu, activation='relu', bias_init=
split_1 = tflearn.fully_connected(inputs[:, 1:2, -1], Neu, activation='relu', bias_init=
split_2 = tflearn.fully_connected(inputs[:, 2:3, -1], Neu, activation='relu', bias_init=
split_3 = tflearn.fully_connected(inputs[:, 3:4, -1], Neu, activation='relu', bias_init=
split_4 = tflearn.fully_connected(inputs[:, 4:5, -1], Neu, activation='relu', bias_init=
split_5 = tflearn.fully_connected(inputs[:, 5:6, -1], Neu, activation='relu', bias_init=
split_6 = tflearn.fully_connected(inputs[:, 6:7, -1], Neu, activation='relu', bias_init=
split_7 = tflearn.fully_connected(inputs[:, 7:8, -1], Neu, activation='relu', bias_init=
split_8 = tflearn.fully_connected(inputs[:, 8:9, -1], Neu, activation='relu', bias_init=
split_9 = tflearn.fully_connected(inputs[:, 9:10, -1], Neu, activation='relu', bias_init=
# 此处Neu 应做卷积核个数, 4 为其size
split_20 = v_1d(inputs[:, 10:11, :], Neu, 4, activation='relu',
bias_stant_initializer(0.1))
split_21 = v_1d(inputs[:, 11:12, :], Neu, 4, activation='relu',
bias_stant_initializer(0.1))
split_20_flat = tflearn.flatten(split_20)
split_21_flat = tflearn.flatten(split_21)
merge_net = (
[split_0, split_1, split_2, split_3, split_4, split_5, split_6, split_7, split_8, split_9,
split_20_flat, split_21_flat], 'concat')
den_net_0 = tflearn.fully_connected(merge_net, Neu, activation='linear',
bias_stant_initializer(0.1))
q_eval = tflearn.fully_connected(den_net_0, lf.a_dim, activation='linear', bias_init=
return inputs, q_eval
lf.inputs_e, lf.q_eval = lf.build_eval_net()
这⾥⽤的搭建神经⽹络的模块是集成在TensorFlow上的⾼级。
应⽤也⼗分简单, 给定⼀个inputs设定输⼊格式, 然后选⽤其中的数据即可, 这⾥因为我们的状态和
每⼀个nsor的AOI有关, 所以可以看到前10个状态都是将⼀个个nsor的值传⼊了⼀个全连接神经⽹络, 再将两个⼀⾏五列的的数据放⼊卷积神级⽹络,为了维度匹配,这⾥的神经元个数都是相同的,接着将这些值按⾏扩展拼接起来,再通过⼀个全连接⽹络,最后就可以输出q_eval值了, q_target的⽹络结构和以上⼀样, 这⾥不再赘述。
空白名字Trick of network
正能量标语八个字在调试的过程中发现神级⽹络参数的设置⼗分重要, ⼀些⼩的技巧可以使得模型更快的收敛。
2.DQN 神经⽹络参数分析
调⽤:揍的组词
API ,Tflearn
Neu = 66
Filter = 66
经过测试, 神经元和卷积核的数量设置以上数据是合理的。
更为重要的是,上图代码的神经⽹络的偏差的设置也⼗分关键, 也即bias的值,我在莫凡⾛迷宫的代码中配置了我的DQN代码,加上bias 要⽐不加agent⾛进出⼝的概率要⼤很多,所以我在这⾥加上了bias,同理, 也可以加初始化的, ⼤家可以尝试⼀下。
def __init__(
lf,
ss,
a_dim,
state_dim,
# dqn 中的学习率表⽰ α * (Q_target - Q_eval) = α * (R + gammma * max(Q(s',a1), Q(s', a3) ...)) - [Q(
# s1, a1), Q(s1, a2),..] ,
learning_rate=0.01,
抢新郎
蹒跚拼音
# Gamma
reward_decay=0.9,
e_greedy=0.9,
replace_target_iter=100,
memory_size=9999,
batch_size=32,
e_greedy_increment=None,
):
Initialization parameter 记忆池设定在了9999, 学习率由A3C的0.001增加到了0.01模型很快就收敛了,batch_size稳定设置在32。Activation
经过测试, 在DQN中, 最后⼀层或者两层⽤效果更好, 其余⽤的是, 注意,我只测试过DQN⽤哪⼀种激活函数⽐较好, 如果对别的神级⽹络的参数调试有好的建议和想法可以⼀起讨论!w linear rel
u