0%

DQN with Keras and Gym

研究是因为有趣

Deep Q-Learning with Keras and Gym · Keon’s Blog

Deep Q Learning,DRL-QoS Cloud Scheduling代码已跑通,AIRL未跑,回过头来重新逐行深入分析理解及复现,以便之后独立使用。

1
2
3
4
5
6
conda info -e #(查看所有的虚拟环境)
activate -name #(虚拟环境名字)(进入到该虚拟环境中)
deactivate #退出
pip,conda install (list)(show)
https://mirrors.tuna.tsinghua.edu.cn/help/pypi/ #换源网址
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package #临时使用

环境搭建

目录 名称 本机版本号 命令或备注
python anaconda ok
python ok
pip,conda换源 ok 尽量用conda和anaconda安装,少用pip
虚拟环境 ok activate xx ;deactivate
pycharm
GPU驱动 GPU 456.71 nvidia-smi
GPU加速 cuda 11.1.96 nvcc -V
cuDNN GUDA,CUDNN,PY,
框架 opencv
tensorflow 版本容易与keras冲突
pytorch
步骤 https://blog.csdn.net/qq_26412763/article/details/90272491
冲突关系 tensorflow keras https://docs.floydhub.com/guides/environments/
gpu驱动 CUDA cuDNN 先更新显卡驱动,然后下载对应的CUDA,国内ip无法下载官网CUDA包,成功后会秒变1kb

Deep Q Learning

1
2
3
tensorflow == 1.10.0
keras == 2.1.2
python == 3.6

image-20201211102446854

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
# -*- coding: utf-8 -*-
import random
import gym
import numpy as np
from collections import deque
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
#from A import B 这种方式意味着从A中引入B。相当于:import A, b=A.b。
#import A as B 这种方式为给引入的包A定义一个别名B
EPISODES = 1000
#循环训练次数
class DQNAgent:
def __init__(self, state_size, action_size):
#self面向对象指DQNAgent,state_size,action_size对应statespace和actionspace的大小
self.state_size = state_size
self.action_size = action_size#传参
self.memory = deque(maxlen=2000) #定义memory为deque()双端队列,定义最大内存
self.gamma = 0.95 # discount rate折扣率,未来和现实的比重
self.epsilon = 1.0 # exploration rate 探索率
self.epsilon_min = 0.01 #最小探索率也保证0.01
self.epsilon_decay = 0.995 #探索率是衰变的,从随机到不随机
self.learning_rate = 0.001 #学习率,每次迭代中学习多少神经网络
self.model = self._build_model() #model是下个函数_build_model()中定义的

def _build_model(self):#调用Keras创建简单的神经网络
# Neural Net for Deep-Q learning Model
#输入层4个信息,2个隐藏层,输出层2个节点01
model = Sequential()#Sequential()创建基础层
model.add(Dense(24, input_dim=self.state_size, activation='relu'))
#Dense全连接层,包含输入层和第一个隐藏层,输入层大小为statesize为4,隐藏层具有24个节点
#activation激活函数relu max(0,x)非线性输出
model.add(Dense(24, activation='relu'))#第二个隐藏层,24个节点
model.add(Dense(self.action_size, activation='linear'))
#最后一层输出层,大小为actionsize为2,activation激活函数linear线性
model.compile(loss='mse',#由以上信息编译model,
#用loss提升model,定义loss用mse平均方差
optimizer=Adam(lr=self.learning_rate))
#优化optimizer方法,Adam自适应状态估计,用规定的学习率
return model#返回创建的model

#memorize()将state,action,reward和next_state储存到memory队列
def memorize(self, state, action, reward, next_state, done):
self.memory.append((state, action, reward, next_state, done))
#append()在deque双向队列memory右侧添加(state, action, reward, next_state, done)
#memory定义在__init__简单的双端队列,具体顺序按如上排列
#done对应是否结束

def act(self, state):
if np.random.rand() <= self.epsilon:#如果随机数小于探索率
#np.random.rand()随机返回一个(默认)或一组服从[0,1)均匀分布的随机样本值。
return random.randrange(self.action_size)#action_size为2
#random.randrange()从指定范围内随机选择的元素,或者数值范围随机输出,
#返回 输出结果0或1
act_values = self.model.predict(state)#训练后predict()模型根据当前状态预测回报
#act_values就是reward
return np.argmax(act_values[0]) # returns action
#act_values[0]固定格式必须写0,输出类似[0.67,0.2],代表01两个action的reward
#argmax(fx)为fx取得最大值时对应的参数,此处为最大reward的action对应的参数

def replay(self, batch_size):#reply用memory队列里的经验训练神经网络
minibatch = random.sample(self.memory, batch_size)
#minibatch为memory中的抽样,随机抽样random.sample(取样来源memory,取样个数)
for state, action, reward, next_state, done in minibatch:
#对mini_batch里的每一个从memory中抽样得到的元素来说
target = reward#如果done为完成??? target就是最后一个,即所有的reward和
if not done:
target = (reward + self.gamma *
np.amax(self.model.predict(next_state)[0]))
#Keras为我们处理了神经网络的所有任务,
#我们只需要定义target,fit()就自动计算LOSS
#TD算法中的target,gamma为折扣率(现实与未来),
#np.amax(predit(next_s))当前如果采取a后下一状态s对应的未来奖励Q,
#比较计算不同a对应未来的Q最大值
#具体讲就是我们先采取了行动a,然后得到了奖励r,并且到达了一个新的状态 next s
#计算最大的目标值 np.amax(),
#乘以一个折扣率 gamma,将未来的reward折算到当下,
#target目标奖励值为reward加未来reward
#循环直到done,把所有reward都加起来,也就是return

target_f = self.model.predict(state)
#target_f为当前state对应的预期reward Q(s,a)
target_f[0][action] = target
#啥意思???target和target_f有什么关系
self.model.fit(state, target_f, epochs=1, verbose=0)
#向其提供信息为了使神经网络能够根据环境数据进行理解和预测
#fit()成对将输入和输出给模型训练,可以根据输入预测输出
#神经网络就可以从确定的state预测reward了
#重复fit(),神奇的减少LOSS,提高分数
#DQN最明显的特征是memorize and replay
#用state和target_f训练神经网络

if self.epsilon > self.epsilon_min:#如果探索率在正常范围内,就给他乘衰减,因此,随着
self.epsilon *= self.epsilon_decay

def load(self, name):
self.model.load_weights(name)
#用h5文件加载图层权重,调用keras

def save(self, name):
self.model.save_weights(name)#保存


if __name__ == "__main__":
env = gym.make('CartPole-v1')#加载CartPole游戏
state_size = env.observation_space.shape[0]
action_size = env.action_space.n#action_size为action_space的个数 2
#此时env.action_space == Discrete(2)即离散(2)
#env.action_space.n == 2 .n为action_space的个数
agent = DQNAgent(state_size, action_size)#运行DQNAgent
# agent.load("./save/cartpole-dqn.h5")
done = False#初始化done
batch_size = 32#设置mini_batch的大小

for e in range(EPISODES):#迭代游戏
state = env.reset()#每次游戏初都重置state
state = np.reshape(state, [1, state_size])
#np.reshape()把单行的state数组重组为1行4列state_size的无数个数组
for time in range(500):#time代表游戏的每一帧,小棍直立时间,等于分数
env.render()#渲染图像,可视化展示环境
action = agent.act(state) #由agent.act()决定动作是0或1
next_state, reward, done, _ = env.step(action) #获取下一步的环境、得分、检测是否完成
#env.step(action),将选择的action输入给env,env 按照这个动作走一步使环境进入下一个状态,所以它的返回值有四个:observation:进入的新状态;reward:采取这个行动得到的奖励;done:当前游戏是否结束;info:其他一些信息,如性能表现,延迟等等,可用于调优
reward = reward if not done else -10#如果没掉reward=reward否则reward-10
next_state = np.reshape(next_state, [1, state_size])#刷新next_state
#next_state独立刷新,state不再刷新,通过由next_state复制来推动
agent.memorize(state, action, reward, next_state, done)#memory队列记录当前信息
state = next_state#上面提到的赋值
if done:#游戏结束,则输出
print("episode: {}/{}, score: {}, e: {:.2}"
.format(e, EPISODES, time, agent.epsilon))
#print("{}".format())格式化输出,用()代替{}
break
if len(agent.memory) > batch_size:
#如果neemory队列里面内容变多,多于batch_size,才reply(),
#因此修改batch后,batch改的越大,刚开始进行游戏速度极快,始终分数很低,因为没有训练,只是随机的玩。在一个提醒后,突然就变慢了,怀疑和勘探率,学习率有关,进入了训练。
agent.replay(batch_size)
# if e % 10 == 0:
# agent.save("./save/cartpole-dqn.h5")

激活函数sigmoid、tanh、relu、Swish

深度学习常见的优化方法(Optimizer)总结:Adam,SGD,Momentum,AdaGard等

deep-q-learning

TD中的LOSS

安装Gym后,一般的使用流程是:

  1. 加载 gym 库:import gym

  2. 进入指定的实验环境:env = gym.make("Taxi-v2").env

  3. 渲染环境,即可视化看看环境的样子:env.render()

其中 env 是 gym 的核心接口,有几个常用的方法也是实验中通用的:

  1. env.reset, 重置环境,返回一个随机的初始状态。

  2. env.step(action),将选择的action输入给env,env 按照这个动作走一步使环境进入下一个状态,所以它的返回值有四个:

1
next_state, reward, done, _ = env.step(action)

observation:进入的新状态

reward:采取这个行动得到的奖励

done:当前游戏是否结束

info:其他一些信息,如性能表现,延迟等等,可用于调优

  1. env.render,这个前面说过可以可视化展示环境

注意到,在 state1-action-state2 这个过程中,action 是需要我们决定的,通常会通过 greedy search 和 q learning 等算法选择,而 state1,state2 就可以用 env 自动获取。

gym模块中环境的常用函数

gym的初始化

1
2
3
4
env = gym.make('CartPole-v0')   
# 定义使用gym库中的某一个环境,'CartPole-v0'可以改为其它环境
env = env.unwrapped
# 据说不做这个动作会有很多限制,unwrapped是打开限制的意思

gym的各个参数的获取

1
2
3
4
5
6
7
8
env.action_space   		
# 查看这个环境中可用的action有多少个,返回Discrete()格式 (离散)
env.observation_space
# 查看这个环境中observation的特征,返回Box()格式
n_actions=env.action_space.n
# 查看这个环境中可用的action有多少个,返回int
n_features=env.observation_space.shape[0]
# 查看这个环境中observation的特征有多少个,返回int

刷新环境

1
2
3
4
env.reset()
# 用于一个世代(done)后环境的重启,获取回合的第一个observation
env.render()
# 用于每一步后刷新环境状态,渲染环境,即可视化看看环境的样子

读取环境

1
2
observation_, reward, done, info = env.step(action)
# 获取下一步的环境因此之上写作next_state、得分、检测是否完成。

2020/12/28

欢迎关注我的其它发布渠道