From f4ac39625a41f60a74450041011b96245923482d Mon Sep 17 00:00:00 2001 From: qiwang067 Date: Mon, 20 Jul 2020 23:56:20 +0800 Subject: [PATCH] add some codes --- README.md | 1 + codes/Q-learning/agent.py | 75 +++++++ codes/Q-learning/gridworld.py | 195 ++++++++++++++++++ codes/Q-learning/train.py | 90 ++++++++ codes/Sarsa/agent.py | 74 +++++++ codes/Sarsa/gridworld.py | 195 ++++++++++++++++++ codes/Sarsa/train.py | 92 +++++++++ codes/ddpg/ddpg.py | 87 ++++++++ codes/ddpg/env.py | 31 +++ codes/ddpg/main.py | 89 ++++++++ codes/ddpg/memory.py | 34 +++ codes/ddpg/model.py | 56 +++++ codes/ddpg/noise.py | 39 ++++ codes/ddpg/plot.py | 47 +++++ codes/ddpg/result/moving_average_rewards.npy | Bin 0 -> 1728 bytes codes/ddpg/result/moving_average_rewards.png | Bin 0 -> 32419 bytes codes/ddpg/result/rewards.npy | Bin 0 -> 1728 bytes codes/ddpg/result/rewards.png | Bin 0 -> 48556 bytes codes/dqn/dqn.py | 98 +++++++++ codes/dqn/main.py | 98 +++++++++ codes/dqn/memory.py | 35 ++++ codes/dqn/model.py | 30 +++ codes/dqn/plot.py | 30 +++ codes/dqn/result/moving_average_rewards.npy | Bin 0 -> 1728 bytes codes/dqn/result/moving_average_rewards.png | Bin 0 -> 31573 bytes codes/dqn/result/rewards.npy | Bin 0 -> 1728 bytes codes/dqn/result/rewards.png | Bin 0 -> 49809 bytes codes/dqn_cnn/dqn.py | 107 ++++++++++ codes/dqn_cnn/main.py | 115 +++++++++++ codes/dqn_cnn/memory.py | 37 ++++ codes/dqn_cnn/model.py | 41 ++++ codes/dqn_cnn/plot.py | 24 +++ .../dqn_cnn/result/moving_average_rewards.npy | Bin 0 -> 528 bytes .../dqn_cnn/result/moving_average_rewards.png | Bin 0 -> 34944 bytes codes/dqn_cnn/result/rewards.npy | Bin 0 -> 528 bytes codes/dqn_cnn/result/rewards.png | Bin 0 -> 45288 bytes codes/dqn_cnn/screen_state.py | 66 ++++++ docs/README.md | 1 + docs/chapter2/chapter2.md | 15 +- docs/chapter3/chapter3.md | 2 + docs/chapter4/chapter4.md | 2 +- 41 files changed, 1799 insertions(+), 7 deletions(-) create mode 100644 codes/Q-learning/agent.py create mode 100644 codes/Q-learning/gridworld.py create mode 100644 codes/Q-learning/train.py create mode 100644 codes/Sarsa/agent.py create mode 100644 codes/Sarsa/gridworld.py create mode 100644 codes/Sarsa/train.py create mode 100644 codes/ddpg/ddpg.py create mode 100644 codes/ddpg/env.py create mode 100644 codes/ddpg/main.py create mode 100644 codes/ddpg/memory.py create mode 100644 codes/ddpg/model.py create mode 100644 codes/ddpg/noise.py create mode 100644 codes/ddpg/plot.py create mode 100644 codes/ddpg/result/moving_average_rewards.npy create mode 100644 codes/ddpg/result/moving_average_rewards.png create mode 100644 codes/ddpg/result/rewards.npy create mode 100644 codes/ddpg/result/rewards.png create mode 100644 codes/dqn/dqn.py create mode 100644 codes/dqn/main.py create mode 100644 codes/dqn/memory.py create mode 100644 codes/dqn/model.py create mode 100644 codes/dqn/plot.py create mode 100644 codes/dqn/result/moving_average_rewards.npy create mode 100644 codes/dqn/result/moving_average_rewards.png create mode 100644 codes/dqn/result/rewards.npy create mode 100644 codes/dqn/result/rewards.png create mode 100644 codes/dqn_cnn/dqn.py create mode 100644 codes/dqn_cnn/main.py create mode 100644 codes/dqn_cnn/memory.py create mode 100644 codes/dqn_cnn/model.py create mode 100644 codes/dqn_cnn/plot.py create mode 100644 codes/dqn_cnn/result/moving_average_rewards.npy create mode 100644 codes/dqn_cnn/result/moving_average_rewards.png create mode 100644 codes/dqn_cnn/result/rewards.npy create mode 100644 codes/dqn_cnn/result/rewards.png create mode 100644 codes/dqn_cnn/screen_state.py diff --git a/README.md b/README.md index f6c19d1..b9c259d 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ ## 主要贡献者 - [@qiwang067](https://github.com/qiwang067) +- [@JohnJim0816](https://github.com/JohnJim0816) ## 关注我们 diff --git a/codes/Q-learning/agent.py b/codes/Q-learning/agent.py new file mode 100644 index 0000000..729c6d8 --- /dev/null +++ b/codes/Q-learning/agent.py @@ -0,0 +1,75 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# -*- coding: utf-8 -*- + +import numpy as np + + +class QLearningAgent(object): + def __init__(self, + obs_n, + act_n, + learning_rate=0.01, + gamma=0.9, + e_greed=0.1): + self.act_n = act_n # 动作维度,有几个动作可选 + self.lr = learning_rate # 学习率 + self.gamma = gamma # reward的衰减率 + self.epsilon = e_greed # 按一定概率随机选动作 + self.Q = np.zeros((obs_n, act_n)) + + # 根据输入观察值,采样输出的动作值,带探索 + def sample(self, obs): + if np.random.uniform(0, 1) < (1.0 - self.epsilon): #根据table的Q值选动作 + action = self.predict(obs) + else: + action = np.random.choice(self.act_n) #有一定概率随机探索选取一个动作 + return action + + # 根据输入观察值,预测输出的动作值 + def predict(self, obs): + Q_list = self.Q[obs, :] + maxQ = np.max(Q_list) + action_list = np.where(Q_list == maxQ)[0] # maxQ可能对应多个action + action = np.random.choice(action_list) + return action + + # 学习方法,也就是更新Q-table的方法 + def learn(self, obs, action, reward, next_obs, done): + """ off-policy + obs: 交互前的obs, s_t + action: 本次交互选择的action, a_t + reward: 本次动作获得的奖励r + next_obs: 本次交互后的obs, s_t+1 + done: episode是否结束 + """ + predict_Q = self.Q[obs, action] + if done: + target_Q = reward # 没有下一个状态了 + else: + target_Q = reward + self.gamma * np.max( + self.Q[next_obs, :]) # Q-learning + self.Q[obs, action] += self.lr * (target_Q - predict_Q) # 修正q + + # 把 Q表格 的数据保存到文件中 + def save(self): + npy_file = './q_table.npy' + np.save(npy_file, self.Q) + print(npy_file + ' saved.') + + # 从文件中读取数据到 Q表格 + def restore(self, npy_file='./q_table.npy'): + self.Q = np.load(npy_file) + print(npy_file + ' loaded.') \ No newline at end of file diff --git a/codes/Q-learning/gridworld.py b/codes/Q-learning/gridworld.py new file mode 100644 index 0000000..31d968f --- /dev/null +++ b/codes/Q-learning/gridworld.py @@ -0,0 +1,195 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# -*- coding: utf-8 -*- + +import gym +import turtle +import numpy as np + +# turtle tutorial : https://docs.python.org/3.3/library/turtle.html + + +def GridWorld(gridmap=None, is_slippery=False): + if gridmap is None: + gridmap = ['SFFF', 'FHFH', 'FFFH', 'HFFG'] + env = gym.make("FrozenLake-v0", desc=gridmap, is_slippery=False) + env = FrozenLakeWapper(env) + return env + + +class FrozenLakeWapper(gym.Wrapper): + def __init__(self, env): + gym.Wrapper.__init__(self, env) + self.max_y = env.desc.shape[0] + self.max_x = env.desc.shape[1] + self.t = None + self.unit = 50 + + def draw_box(self, x, y, fillcolor='', line_color='gray'): + self.t.up() + self.t.goto(x * self.unit, y * self.unit) + self.t.color(line_color) + self.t.fillcolor(fillcolor) + self.t.setheading(90) + self.t.down() + self.t.begin_fill() + for _ in range(4): + self.t.forward(self.unit) + self.t.right(90) + self.t.end_fill() + + def move_player(self, x, y): + self.t.up() + self.t.setheading(90) + self.t.fillcolor('red') + self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit) + + def render(self): + if self.t == None: + self.t = turtle.Turtle() + self.wn = turtle.Screen() + self.wn.setup(self.unit * self.max_x + 100, + self.unit * self.max_y + 100) + self.wn.setworldcoordinates(0, 0, self.unit * self.max_x, + self.unit * self.max_y) + self.t.shape('circle') + self.t.width(2) + self.t.speed(0) + self.t.color('gray') + for i in range(self.desc.shape[0]): + for j in range(self.desc.shape[1]): + x = j + y = self.max_y - 1 - i + if self.desc[i][j] == b'S': # Start + self.draw_box(x, y, 'white') + elif self.desc[i][j] == b'F': # Frozen ice + self.draw_box(x, y, 'white') + elif self.desc[i][j] == b'G': # Goal + self.draw_box(x, y, 'yellow') + elif self.desc[i][j] == b'H': # Hole + self.draw_box(x, y, 'black') + else: + self.draw_box(x, y, 'white') + self.t.shape('turtle') + + x_pos = self.s % self.max_x + y_pos = self.max_y - 1 - int(self.s / self.max_x) + self.move_player(x_pos, y_pos) + + +class CliffWalkingWapper(gym.Wrapper): + def __init__(self, env): + gym.Wrapper.__init__(self, env) + self.t = None + self.unit = 50 + self.max_x = 12 + self.max_y = 4 + + def draw_x_line(self, y, x0, x1, color='gray'): + assert x1 > x0 + self.t.color(color) + self.t.setheading(0) + self.t.up() + self.t.goto(x0, y) + self.t.down() + self.t.forward(x1 - x0) + + def draw_y_line(self, x, y0, y1, color='gray'): + assert y1 > y0 + self.t.color(color) + self.t.setheading(90) + self.t.up() + self.t.goto(x, y0) + self.t.down() + self.t.forward(y1 - y0) + + def draw_box(self, x, y, fillcolor='', line_color='gray'): + self.t.up() + self.t.goto(x * self.unit, y * self.unit) + self.t.color(line_color) + self.t.fillcolor(fillcolor) + self.t.setheading(90) + self.t.down() + self.t.begin_fill() + for i in range(4): + self.t.forward(self.unit) + self.t.right(90) + self.t.end_fill() + + def move_player(self, x, y): + self.t.up() + self.t.setheading(90) + self.t.fillcolor('red') + self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit) + + def render(self): + if self.t == None: + self.t = turtle.Turtle() + self.wn = turtle.Screen() + self.wn.setup(self.unit * self.max_x + 100, + self.unit * self.max_y + 100) + self.wn.setworldcoordinates(0, 0, self.unit * self.max_x, + self.unit * self.max_y) + self.t.shape('circle') + self.t.width(2) + self.t.speed(0) + self.t.color('gray') + for _ in range(2): + self.t.forward(self.max_x * self.unit) + self.t.left(90) + self.t.forward(self.max_y * self.unit) + self.t.left(90) + for i in range(1, self.max_y): + self.draw_x_line( + y=i * self.unit, x0=0, x1=self.max_x * self.unit) + for i in range(1, self.max_x): + self.draw_y_line( + x=i * self.unit, y0=0, y1=self.max_y * self.unit) + + for i in range(1, self.max_x - 1): + self.draw_box(i, 0, 'black') + self.draw_box(self.max_x - 1, 0, 'yellow') + self.t.shape('turtle') + + x_pos = self.s % self.max_x + y_pos = self.max_y - 1 - int(self.s / self.max_x) + self.move_player(x_pos, y_pos) + + +if __name__ == '__main__': + # 环境1:FrozenLake, 可以配置冰面是否是滑的 + # 0 left, 1 down, 2 right, 3 up + env = gym.make("FrozenLake-v0", is_slippery=False) + env = FrozenLakeWapper(env) + + # 环境2:CliffWalking, 悬崖环境 + # env = gym.make("CliffWalking-v0") # 0 up, 1 right, 2 down, 3 left + # env = CliffWalkingWapper(env) + + # 环境3:自定义格子世界,可以配置地图, S为出发点Start, F为平地Floor, H为洞Hole, G为出口目标Goal + # gridmap = [ + # 'SFFF', + # 'FHFF', + # 'FFFF', + # 'HFGF' ] + # env = GridWorld(gridmap) + + env.reset() + for step in range(10): + action = np.random.randint(0, 4) + obs, reward, done, info = env.step(action) + print('step {}: action {}, obs {}, reward {}, done {}, info {}'.format(\ + step, action, obs, reward, done, info)) + # env.render() # 渲染一帧图像 \ No newline at end of file diff --git a/codes/Q-learning/train.py b/codes/Q-learning/train.py new file mode 100644 index 0000000..032e2f9 --- /dev/null +++ b/codes/Q-learning/train.py @@ -0,0 +1,90 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# -*- coding: utf-8 -*- + +import gym +from gridworld import CliffWalkingWapper, FrozenLakeWapper +from agent import QLearningAgent +import time + + +def run_episode(env, agent, render=False): + total_steps = 0 # 记录每个episode走了多少step + total_reward = 0 + + obs = env.reset() # 重置环境, 重新开一局(即开始新的一个episode) + + while True: + action = agent.sample(obs) # 根据算法选择一个动作 + next_obs, reward, done, _ = env.step(action) # 与环境进行一个交互 + # 训练 Q-learning算法 + agent.learn(obs, action, reward, next_obs, done) # 不需要下一步的action + + obs = next_obs # 存储上一个观察值 + total_reward += reward + total_steps += 1 # 计算step数 + if render: + env.render() #渲染新的一帧图形 + if done: + break + return total_reward, total_steps + + +def test_episode(env, agent): + total_reward = 0 + obs = env.reset() + while True: + action = agent.predict(obs) # greedy + next_obs, reward, done, _ = env.step(action) + total_reward += reward + obs = next_obs + time.sleep(0.5) + env.render() + if done: + print('test reward = %.1f' % (total_reward)) + break + + +def main(): + # env = gym.make("FrozenLake-v0", is_slippery=False) # 0 left, 1 down, 2 right, 3 up + # env = FrozenLakeWapper(env) + + env = gym.make("CliffWalking-v0") # 0 up, 1 right, 2 down, 3 left + env = CliffWalkingWapper(env) + + agent = QLearningAgent( + obs_n=env.observation_space.n, + act_n=env.action_space.n, + learning_rate=0.1, + gamma=0.9, + e_greed=0.1) + + is_render = False + for episode in range(500): + ep_reward, ep_steps = run_episode(env, agent, is_render) + print('Episode %s: steps = %s , reward = %.1f' % (episode, ep_steps, + ep_reward)) + + # 每隔20个episode渲染一下看看效果 + if episode % 20 == 0: + is_render = True + else: + is_render = False + # 训练结束,查看算法效果 + test_episode(env, agent) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/codes/Sarsa/agent.py b/codes/Sarsa/agent.py new file mode 100644 index 0000000..f791293 --- /dev/null +++ b/codes/Sarsa/agent.py @@ -0,0 +1,74 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# -*- coding: utf-8 -*- + +import numpy as np + +# 根据Q表格选动作 +class SarsaAgent(object): + def __init__(self, + obs_n, + act_n, + learning_rate=0.01, + gamma=0.9, + e_greed=0.1): + self.act_n = act_n # 动作维度,有几个动作可选 + self.lr = learning_rate # 学习率 + self.gamma = gamma # reward的衰减率 + self.epsilon = e_greed # 按一定概率随机选动作 + self.Q = np.zeros((obs_n, act_n)) # 初始化Q表格 + + # 根据输入观察值,采样输出的动作值,带探索(epsilon-greedy,训练时用这个方法) + def sample(self, obs): + if np.random.uniform(0, 1) < (1.0 - self.epsilon): #根据table的Q值选动作 + action = self.predict(obs) + else: + action = np.random.choice(self.act_n) #有一定概率随机探索选取一个动作 + return action + + # 根据输入观察值,预测输出的动作值(已有里面挑最大,贪心的算法,只有利用,没有探索) + def predict(self, obs): + Q_list = self.Q[obs, :] + maxQ = np.max(Q_list) # 找到最大Q对应的下标 + action_list = np.where(Q_list == maxQ)[0] # maxQ可能对应多个action + action = np.random.choice(action_list) # 从这些action中随机挑一个action(可以打印出来看看) + return action + + # 学习方法,也就是更新Q-table的方法 + def learn(self, obs, action, reward, next_obs, next_action, done): + """ on-policy + obs: 交互前的obs, s_t + action: 本次交互选择的action, a_t + reward: 本次动作获得的奖励r + next_obs: 本次交互后的obs, s_t+1 + next_action: 根据当前Q表格, 针对next_obs会选择的动作, a_t+1 + done: episode是否结束 + """ + predict_Q = self.Q[obs, action] + if done: # done为ture的话,代表这是episode最后一个状态 + target_Q = reward # 没有下一个状态了 + else: + target_Q = reward + self.gamma * self.Q[next_obs, + next_action] # Sarsa + self.Q[obs, action] += self.lr * (target_Q - predict_Q) # 修正q + + def save(self): + npy_file = './q_table.npy' + np.save(npy_file, self.Q) + print(npy_file + ' saved.') + + def restore(self, npy_file='./q_table.npy'): + self.Q = np.load(npy_file) + print(npy_file + ' loaded.') \ No newline at end of file diff --git a/codes/Sarsa/gridworld.py b/codes/Sarsa/gridworld.py new file mode 100644 index 0000000..31d968f --- /dev/null +++ b/codes/Sarsa/gridworld.py @@ -0,0 +1,195 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# -*- coding: utf-8 -*- + +import gym +import turtle +import numpy as np + +# turtle tutorial : https://docs.python.org/3.3/library/turtle.html + + +def GridWorld(gridmap=None, is_slippery=False): + if gridmap is None: + gridmap = ['SFFF', 'FHFH', 'FFFH', 'HFFG'] + env = gym.make("FrozenLake-v0", desc=gridmap, is_slippery=False) + env = FrozenLakeWapper(env) + return env + + +class FrozenLakeWapper(gym.Wrapper): + def __init__(self, env): + gym.Wrapper.__init__(self, env) + self.max_y = env.desc.shape[0] + self.max_x = env.desc.shape[1] + self.t = None + self.unit = 50 + + def draw_box(self, x, y, fillcolor='', line_color='gray'): + self.t.up() + self.t.goto(x * self.unit, y * self.unit) + self.t.color(line_color) + self.t.fillcolor(fillcolor) + self.t.setheading(90) + self.t.down() + self.t.begin_fill() + for _ in range(4): + self.t.forward(self.unit) + self.t.right(90) + self.t.end_fill() + + def move_player(self, x, y): + self.t.up() + self.t.setheading(90) + self.t.fillcolor('red') + self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit) + + def render(self): + if self.t == None: + self.t = turtle.Turtle() + self.wn = turtle.Screen() + self.wn.setup(self.unit * self.max_x + 100, + self.unit * self.max_y + 100) + self.wn.setworldcoordinates(0, 0, self.unit * self.max_x, + self.unit * self.max_y) + self.t.shape('circle') + self.t.width(2) + self.t.speed(0) + self.t.color('gray') + for i in range(self.desc.shape[0]): + for j in range(self.desc.shape[1]): + x = j + y = self.max_y - 1 - i + if self.desc[i][j] == b'S': # Start + self.draw_box(x, y, 'white') + elif self.desc[i][j] == b'F': # Frozen ice + self.draw_box(x, y, 'white') + elif self.desc[i][j] == b'G': # Goal + self.draw_box(x, y, 'yellow') + elif self.desc[i][j] == b'H': # Hole + self.draw_box(x, y, 'black') + else: + self.draw_box(x, y, 'white') + self.t.shape('turtle') + + x_pos = self.s % self.max_x + y_pos = self.max_y - 1 - int(self.s / self.max_x) + self.move_player(x_pos, y_pos) + + +class CliffWalkingWapper(gym.Wrapper): + def __init__(self, env): + gym.Wrapper.__init__(self, env) + self.t = None + self.unit = 50 + self.max_x = 12 + self.max_y = 4 + + def draw_x_line(self, y, x0, x1, color='gray'): + assert x1 > x0 + self.t.color(color) + self.t.setheading(0) + self.t.up() + self.t.goto(x0, y) + self.t.down() + self.t.forward(x1 - x0) + + def draw_y_line(self, x, y0, y1, color='gray'): + assert y1 > y0 + self.t.color(color) + self.t.setheading(90) + self.t.up() + self.t.goto(x, y0) + self.t.down() + self.t.forward(y1 - y0) + + def draw_box(self, x, y, fillcolor='', line_color='gray'): + self.t.up() + self.t.goto(x * self.unit, y * self.unit) + self.t.color(line_color) + self.t.fillcolor(fillcolor) + self.t.setheading(90) + self.t.down() + self.t.begin_fill() + for i in range(4): + self.t.forward(self.unit) + self.t.right(90) + self.t.end_fill() + + def move_player(self, x, y): + self.t.up() + self.t.setheading(90) + self.t.fillcolor('red') + self.t.goto((x + 0.5) * self.unit, (y + 0.5) * self.unit) + + def render(self): + if self.t == None: + self.t = turtle.Turtle() + self.wn = turtle.Screen() + self.wn.setup(self.unit * self.max_x + 100, + self.unit * self.max_y + 100) + self.wn.setworldcoordinates(0, 0, self.unit * self.max_x, + self.unit * self.max_y) + self.t.shape('circle') + self.t.width(2) + self.t.speed(0) + self.t.color('gray') + for _ in range(2): + self.t.forward(self.max_x * self.unit) + self.t.left(90) + self.t.forward(self.max_y * self.unit) + self.t.left(90) + for i in range(1, self.max_y): + self.draw_x_line( + y=i * self.unit, x0=0, x1=self.max_x * self.unit) + for i in range(1, self.max_x): + self.draw_y_line( + x=i * self.unit, y0=0, y1=self.max_y * self.unit) + + for i in range(1, self.max_x - 1): + self.draw_box(i, 0, 'black') + self.draw_box(self.max_x - 1, 0, 'yellow') + self.t.shape('turtle') + + x_pos = self.s % self.max_x + y_pos = self.max_y - 1 - int(self.s / self.max_x) + self.move_player(x_pos, y_pos) + + +if __name__ == '__main__': + # 环境1:FrozenLake, 可以配置冰面是否是滑的 + # 0 left, 1 down, 2 right, 3 up + env = gym.make("FrozenLake-v0", is_slippery=False) + env = FrozenLakeWapper(env) + + # 环境2:CliffWalking, 悬崖环境 + # env = gym.make("CliffWalking-v0") # 0 up, 1 right, 2 down, 3 left + # env = CliffWalkingWapper(env) + + # 环境3:自定义格子世界,可以配置地图, S为出发点Start, F为平地Floor, H为洞Hole, G为出口目标Goal + # gridmap = [ + # 'SFFF', + # 'FHFF', + # 'FFFF', + # 'HFGF' ] + # env = GridWorld(gridmap) + + env.reset() + for step in range(10): + action = np.random.randint(0, 4) + obs, reward, done, info = env.step(action) + print('step {}: action {}, obs {}, reward {}, done {}, info {}'.format(\ + step, action, obs, reward, done, info)) + # env.render() # 渲染一帧图像 \ No newline at end of file diff --git a/codes/Sarsa/train.py b/codes/Sarsa/train.py new file mode 100644 index 0000000..d390b9d --- /dev/null +++ b/codes/Sarsa/train.py @@ -0,0 +1,92 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# -*- coding: utf-8 -*- + +import gym +from gridworld import CliffWalkingWapper, FrozenLakeWapper +from agent import SarsaAgent +import time + + +def run_episode(env, agent, render=False): + total_steps = 0 # 记录每个episode走了多少step + total_reward = 0 + + obs = env.reset() # 重置环境, 重新开一局(即开始新的一个episode) + action = agent.sample(obs) # 根据算法选择一个动作 + + while True: + next_obs, reward, done, _ = env.step(action) # 与环境进行一个交互 + next_action = agent.sample(next_obs) # 根据算法选择一个动作 + # 训练 Sarsa 算法 + agent.learn(obs, action, reward, next_obs, next_action, done) + + action = next_action + obs = next_obs # 存储上一个观察值 + total_reward += reward + total_steps += 1 # 计算step数 + if render: + env.render() #渲染新的一帧图形 + if done: + break + return total_reward, total_steps + + +def test_episode(env, agent): + total_reward = 0 + obs = env.reset() + while True: + action = agent.predict(obs) # greedy,只取最优的动作 + next_obs, reward, done, _ = env.step(action) + total_reward += reward + obs = next_obs + time.sleep(0.5) # 每个step延迟0.5秒来看看效果 + env.render() + if done: + print('test reward = %.1f' % (total_reward)) + break + + +def main(): + # env = gym.make("FrozenLake-v0", is_slippery=False) # 0 left, 1 down, 2 right, 3 up + # env = FrozenLakeWapper(env) + + env = gym.make("CliffWalking-v0") # 0 up, 1 right, 2 down, 3 left + env = CliffWalkingWapper(env) # 这行不加也可以,这个是为了显示效果更好一点 + + agent = SarsaAgent( + obs_n=env.observation_space.n, + act_n=env.action_space.n, + learning_rate=0.1, + gamma=0.9, + e_greed=0.1) + + is_render = False + for episode in range(500): + ep_reward, ep_steps = run_episode(env, agent, is_render) + print('Episode %s: steps = %s , reward = %.1f' % (episode, ep_steps, + ep_reward)) + + # 每隔20个episode渲染一下看看效果(每个episode都渲染的话,时间会比较长) + if episode % 20 == 0: + is_render = True + else: + is_render = False + # 训练结束,查看算法效果 + test_episode(env, agent) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/codes/ddpg/ddpg.py b/codes/ddpg/ddpg.py new file mode 100644 index 0000000..e1b5a7e --- /dev/null +++ b/codes/ddpg/ddpg.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-09 20:25:52 +@LastEditor: John +@LastEditTime: 2020-06-14 11:43:17 +@Discription: +@Environment: python 3.7.7 +''' +import numpy as np +import torch +import torch.nn as nn +import torch.optim as optim + +from model import Actor, Critic +from memory import ReplayBuffer + + +class DDPG: + def __init__(self, n_states, n_actions, hidden_dim=30, device="cpu", critic_lr=1e-3, + actor_lr=1e-4, gamma=0.99, soft_tau=1e-2, memory_capacity=100000, batch_size=128): + self.device = device + self.critic = Critic(n_states, n_actions, hidden_dim).to(device) + self.actor = Actor(n_states, n_actions, hidden_dim).to(device) + self.target_critic = Critic(n_states, n_actions, hidden_dim).to(device) + self.target_actor = Actor(n_states, n_actions, hidden_dim).to(device) + + for target_param, param in zip(self.target_critic.parameters(), self.critic.parameters()): + target_param.data.copy_(param.data) + for target_param, param in zip(self.target_actor.parameters(), self.actor.parameters()): + target_param.data.copy_(param.data) + + self.critic_optimizer = optim.Adam( + self.critic.parameters(), lr=critic_lr) + self.actor_optimizer = optim.Adam(self.actor.parameters(), lr=actor_lr) + self.critic_criterion = nn.MSELoss() + self.memory = ReplayBuffer(memory_capacity) + self.batch_size = batch_size + self.soft_tau = soft_tau + self.gamma = gamma + + def select_action(self, state): + return self.actor.select_action(state) + + def update(self): + if len(self.memory) < self.batch_size: + return + state, action, reward, next_state, done = self.memory.sample( + self.batch_size) + # 将所有变量转为张量 + state = torch.FloatTensor(state).to(self.device) + next_state = torch.FloatTensor(next_state).to(self.device) + action = torch.FloatTensor(action).to(self.device) + reward = torch.FloatTensor(reward).unsqueeze(1).to(self.device) + + done = torch.FloatTensor(np.float32(done)).unsqueeze(1).to(self.device) + policy_loss = self.critic(state, self.actor(state)) + policy_loss = -policy_loss.mean() + + next_action = self.target_actor(next_state) + target_value = self.target_critic(next_state, next_action.detach()) + expected_value = reward + (1.0 - done) * self.gamma * target_value + expected_value = torch.clamp(expected_value, -np.inf, np.inf) + + value = self.critic(state, action) + + value_loss = self.critic_criterion(value, expected_value.detach()) + + self.actor_optimizer.zero_grad() + policy_loss.backward() + self.actor_optimizer.step() + + self.critic_optimizer.zero_grad() + value_loss.backward() + self.critic_optimizer.step() + for target_param, param in zip(self.target_critic.parameters(), self.critic.parameters()): + target_param.data.copy_( + target_param.data * (1.0 - self.soft_tau) + + param.data * self.soft_tau + ) + for target_param, param in zip(self.target_actor.parameters(), self.actor.parameters()): + target_param.data.copy_( + target_param.data * (1.0 - self.soft_tau) + + param.data * self.soft_tau + ) diff --git a/codes/ddpg/env.py b/codes/ddpg/env.py new file mode 100644 index 0000000..0b27401 --- /dev/null +++ b/codes/ddpg/env.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-10 15:28:30 +@LastEditor: John +@LastEditTime: 2020-06-12 22:49:18 +@Discription: +@Environment: python 3.7.7 +''' +import gym +import numpy as np + +class NormalizedActions(gym.ActionWrapper): + + def action(self, action): + + low_bound = self.action_space.low + upper_bound = self.action_space.high + action = low_bound + (action + 1.0) * 0.5 * (upper_bound - low_bound) + action = np.clip(action, low_bound, upper_bound) + + return action + + def reverse_action(self, action): + low_bound = self.action_space.low + upper_bound = self.action_space.high + action = 2 * (action - low_bound) / (upper_bound - low_bound) - 1 + action = np.clip(action, low_bound, upper_bound) + return action \ No newline at end of file diff --git a/codes/ddpg/main.py b/codes/ddpg/main.py new file mode 100644 index 0000000..7e4b455 --- /dev/null +++ b/codes/ddpg/main.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 20:58:21 +@LastEditor: John +@LastEditTime: 2020-07-20 23:01:02 +@Discription: +@Environment: python 3.7.7 +''' +import torch +import gym + +from ddpg import DDPG +from env import NormalizedActions +from noise import OUNoise +from plot import plot + +import argparse + +def get_args(): + '''模型建立好之后只需要在这里调参 + ''' + parser = argparse.ArgumentParser() + + parser.add_argument("--gamma", default=0.99, type=float) # q-learning中的gamma + parser.add_argument("--critic_lr", default=1e-3, type=float) # critic学习率 + parser.add_argument("--actor_lr", default=1e-4, type=float) + + parser.add_argument("--memory_capacity", default=10000, type=int,help="capacity of Replay Memory") + + parser.add_argument("--batch_size", default=128, type=int,help="batch size of memory sampling") + parser.add_argument("--max_episodes", default=200, type=int) + parser.add_argument("--max_steps", default=200, type=int) + parser.add_argument("--target_update", default=4, type=int,help="when(every default 10 eisodes) to update target net ") + config = parser.parse_args() + + return config + +if __name__ == "__main__": + + cfg = get_args() + env = NormalizedActions(gym.make("Pendulum-v0")) + + # 增加action噪声 + ou_noise = OUNoise(env.action_space) + + n_states = env.observation_space.shape[0] + n_actions = env.action_space.shape[0] + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + agent=DDPG(n_states,n_actions,device="cpu", critic_lr=1e-3, + actor_lr=1e-4, gamma=0.99, soft_tau=1e-2, memory_capacity=100000, batch_size=128) + + rewards = [] + moving_average_rewards = [] + for i_episode in range(1,cfg.max_episodes+1): + state=env.reset() + ou_noise.reset() + ep_reward = 0 + for i_step in range(1,cfg.max_steps+1): + action = agent.select_action(state) + action = ou_noise.get_action(action, i_step) # 即paper中的random process + next_state, reward, done, _ = env.step(action) + ep_reward += reward + agent.memory.push(state, action, reward, next_state, done) + agent.update() + state = next_state + if done: + break + print('Episode:', i_episode, ' Reward: %i' % int(ep_reward),) + rewards.append(ep_reward) + # + if i_episode == 1: + moving_average_rewards.append(ep_reward) + else: + moving_average_rewards.append( + 0.9*moving_average_rewards[-1]+0.1*ep_reward) + print('Complete!') + import os + import numpy as np + output_path = os.path.dirname(__file__)+"/result/" + if not os.path.exists(output_path): + os.mkdir(output_path) + np.save(output_path+"rewards.npy", rewards) + np.save(output_path+"moving_average_rewards.npy", moving_average_rewards) + + plot(rewards) + plot(moving_average_rewards,ylabel="moving_average_rewards") \ No newline at end of file diff --git a/codes/ddpg/memory.py b/codes/ddpg/memory.py new file mode 100644 index 0000000..34d31b7 --- /dev/null +++ b/codes/ddpg/memory.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-10 15:27:16 +@LastEditor: John +@LastEditTime: 2020-06-13 00:29:45 +@Discription: +@Environment: python 3.7.7 +''' +import random +import numpy as np + +class ReplayBuffer: + + def __init__(self, capacity): + self.capacity = capacity + self.buffer = [] + self.position = 0 + + def push(self, state, action, reward, next_state, done): + if len(self.buffer) < self.capacity: + self.buffer.append(None) + self.buffer[self.position] = (state, action, reward, next_state, done) + self.position = (self.position + 1) % self.capacity + + def sample(self, batch_size): + batch = random.sample(self.buffer, batch_size) + state_batch, action_batch, reward_batch, next_state_batch, done_batch = map(np.stack, zip(*batch)) + return state_batch, action_batch, reward_batch, next_state_batch, done_batch + + def __len__(self): + return len(self.buffer) \ No newline at end of file diff --git a/codes/ddpg/model.py b/codes/ddpg/model.py new file mode 100644 index 0000000..5eed034 --- /dev/null +++ b/codes/ddpg/model.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-10 15:03:59 +@LastEditor: John +@LastEditTime: 2020-06-14 11:42:45 +@Discription: +@Environment: python 3.7.7 +''' +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Critic(nn.Module): + def __init__(self, n_obs, n_actions, hidden_size, init_w=3e-3): + super(Critic, self).__init__() + + self.linear1 = nn.Linear(n_obs + n_actions, hidden_size) + self.linear2 = nn.Linear(hidden_size, hidden_size) + self.linear3 = nn.Linear(hidden_size, 1) + + self.linear3.weight.data.uniform_(-init_w, init_w) + self.linear3.bias.data.uniform_(-init_w, init_w) + + def forward(self, state, action): + x = torch.cat([state, action], 1) + x = F.relu(self.linear1(x)) + x = F.relu(self.linear2(x)) + x = self.linear3(x) + return x + +class Actor(nn.Module): + def __init__(self, n_obs, n_actions, hidden_size, init_w=3e-3): + super(Actor, self).__init__() + self.linear1 = nn.Linear(n_obs, hidden_size) + self.linear2 = nn.Linear(hidden_size, hidden_size) + self.linear3 = nn.Linear(hidden_size, n_actions) + + self.linear3.weight.data.uniform_(-init_w, init_w) + self.linear3.bias.data.uniform_(-init_w, init_w) + + def forward(self, x): + x = F.relu(self.linear1(x)) + x = F.relu(self.linear2(x)) + x = F.tanh(self.linear3(x)) + return x + + def select_action(self, state): + + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + state = torch.FloatTensor(state).unsqueeze(0).to(device) + # print(state) + action = self.forward(state) + return action.detach().cpu().numpy()[0, 0] \ No newline at end of file diff --git a/codes/ddpg/noise.py b/codes/ddpg/noise.py new file mode 100644 index 0000000..50fcec8 --- /dev/null +++ b/codes/ddpg/noise.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 20:58:59 +@LastEditor: John +@LastEditTime: 2020-06-11 20:59:20 +@Discription: +@Environment: python 3.7.7 +''' +import numpy as np + +class OUNoise(object): + def __init__(self, action_space, mu=0.0, theta=0.15, max_sigma=0.3, min_sigma=0.3, decay_period=100000): + self.mu = mu + self.theta = theta + self.sigma = max_sigma + self.max_sigma = max_sigma + self.min_sigma = min_sigma + self.decay_period = decay_period + self.n_actions = action_space.shape[0] + self.low = action_space.low + self.high = action_space.high + self.reset() + + def reset(self): + self.obs = np.ones(self.n_actions) * self.mu + + def evolve_obs(self): + x = self.obs + dx = self.theta * (self.mu - x) + self.sigma * np.random.randn(self.n_actions) + self.obs = x + dx + return self.obs + + def get_action(self, action, t=0): + ou_obs = self.evolve_obs() + self.sigma = self.max_sigma - (self.max_sigma - self.min_sigma) * min(1.0, t / self.decay_period) + return np.clip(action + ou_obs, self.low, self.high) \ No newline at end of file diff --git a/codes/ddpg/plot.py b/codes/ddpg/plot.py new file mode 100644 index 0000000..8cbe42c --- /dev/null +++ b/codes/ddpg/plot.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 16:30:09 +@LastEditor: John +@LastEditTime: 2020-06-12 11:34:52 +@Discription: +@Environment: python 3.7.7 +''' +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns; sns.set() +import numpy as np +import os + +# def plot(item,ylabel='rewards'): +# plt.figure() +# plt.plot(np.arange(len(item)), item) +# plt.title(ylabel+' of DDPG') +# plt.ylabel(ylabel) +# plt.xlabel('episodes') +# plt.savefig(os.path.dirname(__file__)+"/result/"+ylabel+".png") +# plt.show() + +def plot(item,ylabel='rewards'): + df = pd.DataFrame(dict(time=np.arange(500), + value=np.random.randn(500).cumsum())) + g = sns.relplot(x="time", y="value", kind="line", data=df) + g.fig.autofmt_xdate() + # time = range(len(item)) + # sns.set(style="darkgrid", font_scale=1.5) + # sns.lineplot(time=time, data=item, color="r", condition="behavior_cloning") + # # sns.tsplot(time=time, data=x2, color="b", condition="dagger") + # plt.ylabel("Reward") + # plt.xlabel("Iteration Number") + # plt.title("Imitation Learning") + + plt.show() +if __name__ == "__main__": + + output_path = os.path.dirname(__file__)+"/result/" + rewards=np.load(output_path+"rewards.npy", ) + moving_average_rewards=np.load(output_path+"moving_average_rewards.npy",) + plot(rewards) + plot(moving_average_rewards,ylabel='moving_average_rewards') diff --git a/codes/ddpg/result/moving_average_rewards.npy b/codes/ddpg/result/moving_average_rewards.npy new file mode 100644 index 0000000000000000000000000000000000000000..ac2d5735d86c4ffa51b68e67cd0073f77ee7c835 GIT binary patch literal 1728 zcmbV}`#aQ$0>({|L`2l0P-040#JZ$CZkx-rZnHX+h>$gD%cIE5>JWGjEPM- zmdtc9VYk7LvPu`vl+B#Wk;7h;$<{oG)!DaQDvBGx;PQZOz`mG8He zKr#7`#a{OkTwF@Hu23#PQeNUK1Lw2IXXL$U87f9rUw|YtwHO?=B2$@LF`{=KGL>&B zLdd~3yJWQ@0XDkq`0BuXcxM z<-^Nt6*(l&gZZza6&qFaLE3iTi;m1gK_}!>zZass_4@4+p%9y21^@fS zIw734dYCsjWMF$`_t`hm>8RET+93HsfI_|I`S;@j=vud?K3NdppFhS185W$zB~A8P zX)^`x_>9c&DT%=M){CAyXpC$t7JWHP!Omjia(4oShmk=f9Yex#kQv@)PonTqVoM)` z#Ohm;p>Rh6b%U+bAwwh#wcSS5J`l)Wuf0F1mBcpV?1_VwBsgr_gKw`9XuE8)G#*5v zk{F`i37DVZH#?Y7cu?_fk~)A-4k<*Xs0k-5Zs z9ZXZ$pz(3-b1sRpz%Ak8t2CCM*>;w@&{(6=;ZFZaVc#WxgU!20m~`{gGwzcJ*pnpI zdqv>wCaY&Es|fV5r-sY()9}=^YhT42ff|n1*kCw?Tio`6?xQ6B7USKq=P-@Q=yL~r zeJF(14GTI~c=O|Cn%{6~JPaltb!pP@D%TrG?4ZzW6r52SK*RE?&z0T>G&{Ab; z@y9SL&ew~A<{oa_ygvn<4E-nSatcD0`#0^kNzi52V&=Rl)cNmKWBf+q_5+(6ucJx) z(X(|{S)0P{ks_VnZArAxaUEy3lSmgw->h2M8I!g2IdMs1~#!pkVtfqII>bV+)aa}I$Vm@E8h zd3dI(^1Dkt4>g_kxzhPG_%b35pMQ}Cvqw8r>%ZjT7wUNFs)97c+#E{(%!k03r&WaL z9*M>ar;Z2f6KHB=ots zI%XeHyyR0zstRRqUisU|^D?nj9`-NAj#>SX2G|~D`FW(m^?BCeb>~viOBG$@=%*s*f_Tb6j|ZvGrN8%trNLmm zmcp@+2QPY|O~;0STbM<=$bo>%0bLEJSQ0OPor-WhMq@*}dY-(P4|-j@vTW;Vw4{yl Q8vY}IXUz=zWT*iD1yJ>5vH$=8 literal 0 HcmV?d00001 diff --git a/codes/ddpg/result/moving_average_rewards.png b/codes/ddpg/result/moving_average_rewards.png new file mode 100644 index 0000000000000000000000000000000000000000..f39cbd79f88a72d1e91d9893a3acf6b14474d3d6 GIT binary patch literal 32419 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 literal 0 HcmV?d00001 diff --git a/codes/ddpg/result/rewards.npy b/codes/ddpg/result/rewards.npy new file mode 100644 index 0000000000000000000000000000000000000000..08e1a2e5a3258694995a8503624667f41420b4ca GIT binary patch literal 1728 zcmbV~`#05z0>x3Q8cl`NP^(McdCXCgXAC2S$g4HSTi(axoa5m8^~m>Y9L~YvNM1RV z5_t?^4dZqTTTPQp#)@P{jpyXLL-H7f?#*@og}Z_&Hb#o8fGy%FEavF z?-v5Yl_^Q}#W?BYY;V_Gg7pNQTSkmrOw4IU8N_GdTH6C$FfE4WbCW>hYB8K@24as@ zmtsid9QD|z6#6B85{BkANVa|P#~76ZkG^%Kx-mYyvuL9uwwX9OT`an1k%4_mwYxK? zggAb{=+KIE7Jjo^ms@-&f_ryQOVy+hvF2&MD$XJ}uAjg7L_vf+jW%PWm|VzOUpZPk znvT(x!=2tfxv-hywP@VP#JO*^eb?B0c&a`fw13D)uU3`&?INDahjh;7jXIO^-YA)6{-#noa=f<3}UnZe{D^xsfz{mS>ySR;Z8tqGIQlI36 zkPPOW8R_JM71W$E%oHG}TKcb31|-_#shyHDG@MHMRE!+>SgV^n-sP1Di;kt$xIEl7vi=ydQmz#;YGZWbJGyG*4%Xqqn%hQBGLn&BtbGiTtXC5Hqty z++eLt{Hn3%yJj(oU(XsUO?n7$Qa1AE_X=D%-ydo(PE7@)PTAyf5e3~=+l9md5;^)k z{;QrOyc9yu7;O+xJ8fF*{xyk*49(f32^wRvi#ta1D1@`-wSFq%VE5&i?})+8?%oKS zEA5W4ko@d$YWvG{T&bVAxMwekumt#LHzr^-LngcC8#ekTTm9Ds1hSq@|B_-tz_5FE zHAI<$Hy|N2mM6jO-Gi50D04+3X>O8?~AkZ_ZkXB)=`LRnp5yIwGbDNVWDzgKf` zicz(1$&if$?=}v`H3x3>v|e`K`r*q&@5f7We01pKSBiIWkU=S@XDJGBrD>|`pd|;j zLaKuGiVr818p-z~B+lQ8dShEn;QVIIKm11sluq*M22*H630IURkI{H^^lo_Dlo6)Gr zoS{&m<+^e68G*irv(3wX90VWsb10Nf$81PohbJo)?^_B*o&+0AuK&H1g&3%gs(u>C zi@{p<@KSw00kf}vR3<;Nq4VPp`EnL97(1ry_9%l!`2*^eRXiKJ=7;AN2tKa;O|wGj zC?6KRL34L!0?^n?~r5VIDuQWJ$R=zr(!_?(TUX3MXpKj*^1QAbbBfDMhz`;-qO z11{S~c#@qIVnzD-3rndm>uO*GIPf6d_UQEOaX;jH{?ofYi4EcYlh?VM1SU)Eb+305 zkX{p>3Ug0@qmFC=DKMn*Jz|8JO=YC(+*BKHlWSfgp6^jM@i2R3Gf6B*GZX zY{)nqu1`a!>%JS0mM`Ow;f~ITFcN8VT0Gb6ZxJjptZvm2VEB-_Oz3Vt$|9HVdKIL> T=lbRY7h56h&c-QgjFR{-zUyIW literal 0 HcmV?d00001 diff --git a/codes/ddpg/result/rewards.png b/codes/ddpg/result/rewards.png new file mode 100644 index 0000000000000000000000000000000000000000..098edf1b6f335ee3042c0ca2d6e3251f6c024e53 GIT binary patch literal 48556 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 literal 0 HcmV?d00001 diff --git a/codes/dqn/dqn.py b/codes/dqn/dqn.py new file mode 100644 index 0000000..36dc2fd --- /dev/null +++ b/codes/dqn/dqn.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-12 00:50:49 +@LastEditor: John +@LastEditTime: 2020-06-14 13:56:45 +@Discription: +@Environment: python 3.7.7 +''' +'''off-policy +''' +import torch +import torch.nn as nn +import torch.optim as optim +import torch.nn.functional as F +import random +import math +import numpy as np +from memory import ReplayBuffer +from model import FCN + +class DQN: + def __init__(self, n_states, n_actions, gamma=0.99, epsilon_start=0.9, epsilon_end=0.05, epsilon_decay=200, memory_capacity=10000, policy_lr=0.01,batch_size=128, device="cpu"): + self.actions_count = 0 + self.n_actions = n_actions + self.device = device + self.gamma = gamma + self.epsilon = 0 + self.epsilon_start = epsilon_start + self.epsilon_end = epsilon_end + self.epsilon_decay = epsilon_decay + self.batch_size = batch_size + self.policy_net = FCN(n_states,n_actions).to(self.device) + self.target_net = FCN(n_states,n_actions).to(self.device) + self.target_net.load_state_dict(self.policy_net.state_dict()) + self.target_net.eval() # 不启用 BatchNormalization 和 Dropout + self.optimizer = optim.Adam(self.policy_net.parameters(),lr=policy_lr) + self.loss = 0 + self.memory = ReplayBuffer(memory_capacity) + + def select_action(self,state): + '''选择工作 + Args: + state [array]: 状态 + Returns: + [array]: 动作 + ''' + self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \ + math.exp(-1. * self.actions_count / self.epsilon_decay) + self.actions_count += 1 + if random.random() > self.epsilon: + with torch.no_grad(): + state = torch.tensor([state],device=self.device,dtype=torch.float32) # 先转为张量便于丢给神经网络,state元素数据原本为float64;注意state=torch.tensor(state).unsqueeze(0)跟state=torch.tensor([state])等价 + q_value = self.policy_net(state) # tensor([[-0.0798, -0.0079]], grad_fn=) + action = q_value.max(1)[1].item() + else: + action = random.randrange(self.n_actions) + return action + def update(self): + + if len(self.memory) < self.batch_size: + return + + state_batch, action_batch, reward_batch, next_state_batch, done_batch = self.memory.sample(self.batch_size) + + state_batch = torch.tensor(state_batch,device=self.device,dtype=torch.float) # 例如tensor([[-4.5543e-02, -2.3910e-01, 1.8344e-02, 2.3158e-01],...,[-1.8615e-02, -2.3921e-01, -1.1791e-02, 2.3400e-01]]) + action_batch = torch.tensor(action_batch,device=self.device).unsqueeze(1) # 例如tensor([[1],...,[0]]) + reward_batch = torch.tensor(reward_batch,device=self.device,dtype=torch.float) # tensor([1., 1.,...,1]) + next_state_batch = torch.tensor(next_state_batch,device=self.device,dtype=torch.float) + done_batch = torch.tensor(np.float32(done_batch),device=self.device).unsqueeze(1) # 将bool转为float然后转为张量 + # Compute Q(s_t, a) - the model computes Q(s_t), then we select the + # columns of actions taken. These are the actions which would've been taken + # for each batch state according to policy_net + q_values = self.policy_net(state_batch).gather(1, action_batch) # 等价于self.forward + # Compute V(s_{t+1}) for all next states. + # Expected values of actions for non_final_next_states are computed based + # on the "older" target_net; selecting their best reward with max(1)[0]. + # This is merged based on the mask, such that we'll have either the expected + # state value or 0 in case the state was final. + + next_state_values = self.target_net( + next_state_batch).max(1)[0].detach() # tensor([ 0.0060, -0.0171,...,]) + # Compute the expected Q values + expected_q_values = reward_batch + self.gamma * next_state_values * (1-done_batch[0]) + + # Compute Huber loss + # self.loss = nn.MSELoss(q_values, expected_q_values.unsqueeze(1)) + self.loss = nn.MSELoss()(q_values,expected_q_values.unsqueeze(1)) + # Optimize the model + self.optimizer.zero_grad() # zero_grad clears old gradients from the last step (otherwise you’d just accumulate the gradients from all loss.backward() calls). + self.loss.backward() # loss.backward() computes the derivative of the loss w.r.t. the parameters (or anything requiring gradients) using backpropagation. + for param in self.policy_net.parameters(): # clip防止梯度爆炸 + param.grad.data.clamp_(-1, 1) + self.optimizer.step() # causes the optimizer to take a step based on the gradients of the parameters. + + diff --git a/codes/dqn/main.py b/codes/dqn/main.py new file mode 100644 index 0000000..2d7c4b2 --- /dev/null +++ b/codes/dqn/main.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-12 00:48:57 +@LastEditor: John +@LastEditTime: 2020-07-20 23:02:16 +@Discription: +@Environment: python 3.7.7 +''' +'''未完成 +''' +import gym +import torch +from dqn import DQN +from plot import plot +import argparse +def get_args(): + '''模型建立好之后只需要在这里调参 + ''' + parser = argparse.ArgumentParser() + + parser.add_argument("--gamma", default=0.99, + type=float) # q-learning中的gamma + parser.add_argument("--epsilon_start", default=0.95, + type=float) # 基于贪心选择action对应的参数epsilon + parser.add_argument("--epsilon_end", default=0.01, type=float) + parser.add_argument("--epsilon_decay", default=200, type=float) + parser.add_argument("--policy_lr", default=0.01, type=float) + parser.add_argument("--memory_capacity", default=1000, + type=int, help="capacity of Replay Memory") + + parser.add_argument("--batch_size", default=32, type=int, + help="batch size of memory sampling") + parser.add_argument("--max_episodes", default=200, type=int) + parser.add_argument("--max_steps", default=200, type=int) + parser.add_argument("--target_update", default=2, type=int, + help="when(every default 10 eisodes) to update target net ") + config = parser.parse_args() + + return config + + +if __name__ == "__main__": + + cfg = get_args() + # if gpu is to be used + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + env = gym.make('CartPole-v0').unwrapped + env.seed(1) + n_states = env.observation_space.shape[0] + n_actions = env.action_space.n + agent = DQN(n_states=n_states, n_actions=n_actions, device=device, gamma=cfg.gamma, epsilon_start=cfg.epsilon_start, + epsilon_end=cfg.epsilon_end, epsilon_decay=cfg.epsilon_decay,policy_lr=cfg.policy_lr, memory_capacity=cfg.memory_capacity, batch_size=cfg.batch_size) + rewards = [] + moving_average_rewards = [] + for i_episode in range(1, cfg.max_episodes+1): + # Initialize the environment and state + state = env.reset() + ep_reward = 0 + for t in range(1, cfg.max_steps+1): + # Select and perform an action + action = agent.select_action(state) + next_state, reward, done, _ = env.step(action) + ep_reward += reward + # Store the transition in memory + agent.memory.push(state,action,reward,next_state,done) + # Move to the next state + state = next_state + # Perform one step of the optimization (on the target network) + agent.update() + if done: + break + + # Update the target network, copying all weights and biases in DQN + if i_episode % cfg.target_update == 0: + agent.target_net.load_state_dict(agent.policy_net.state_dict()) + print('Episode:', i_episode, ' Reward: %i' % + int(ep_reward), 'Explore: %.2f' % agent.epsilon) + rewards.append(ep_reward) + # 计算滑动窗口的reward + if i_episode == 1: + moving_average_rewards.append(ep_reward) + else: + moving_average_rewards.append( + 0.9*moving_average_rewards[-1]+0.1*ep_reward) + + import os + import numpy as np + output_path = os.path.dirname(__file__)+"/result/" + if not os.path.exists(output_path): + os.mkdir(output_path) + np.save(output_path+"rewards.npy", rewards) + np.save(output_path+"moving_average_rewards.npy", moving_average_rewards) + print('Complete!') + plot(rewards) + plot(moving_average_rewards, ylabel="moving_average_rewards") diff --git a/codes/dqn/memory.py b/codes/dqn/memory.py new file mode 100644 index 0000000..657bfc0 --- /dev/null +++ b/codes/dqn/memory.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-10 15:27:16 +@LastEditor: John +@LastEditTime: 2020-06-14 11:36:24 +@Discription: +@Environment: python 3.7.7 +''' +import random +import numpy as np + +class ReplayBuffer: + + def __init__(self, capacity): + self.capacity = capacity + self.buffer = [] + self.position = 0 + + def push(self, state, action, reward, next_state, done): + if len(self.buffer) < self.capacity: + self.buffer.append(None) + self.buffer[self.position] = (state, action, reward, next_state, done) + self.position = (self.position + 1) % self.capacity + + def sample(self, batch_size): + batch = random.sample(self.buffer, batch_size) + state, action, reward, next_state, done = zip(*batch) + return state, action, reward, next_state, done + + def __len__(self): + return len(self.buffer) + diff --git a/codes/dqn/model.py b/codes/dqn/model.py new file mode 100644 index 0000000..7f8fc0f --- /dev/null +++ b/codes/dqn/model.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-12 00:47:02 +@LastEditor: John +@LastEditTime: 2020-06-14 11:23:04 +@Discription: +@Environment: python 3.7.7 +''' +import torch.nn as nn +import torch.nn.functional as F + +class FCN(nn.Module): + def __init__(self, n_states=4, n_actions=18): + """ + Initialize a deep Q-learning network for testing algorithm + n_states: number of features of input. + n_actions: number of action-value to output, one-to-one correspondence to action in game. + """ + super(FCN, self).__init__() + self.fc1 = nn.Linear(n_states, 128) + self.fc2 = nn.Linear(128, 128) + self.fc3 = nn.Linear(128, n_actions) + + def forward(self, x): + x = F.relu(self.fc1(x)) + x = F.relu(self.fc2(x)) + return self.fc3(x) \ No newline at end of file diff --git a/codes/dqn/plot.py b/codes/dqn/plot.py new file mode 100644 index 0000000..062e9fd --- /dev/null +++ b/codes/dqn/plot.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 16:30:09 +@LastEditor: John +@LastEditTime: 2020-06-14 11:38:42 +@Discription: +@Environment: python 3.7.7 +''' +import matplotlib.pyplot as plt +import numpy as np +import os + +def plot(item,ylabel='rewards'): + plt.figure() + plt.plot(np.arange(len(item)), item) + plt.title(ylabel+' of DQN') + plt.ylabel('rewards') + plt.xlabel('episodes') + plt.savefig(os.path.dirname(__file__)+"/result/"+ylabel+".png") + plt.show() +if __name__ == "__main__": + + output_path = os.path.dirname(__file__)+"/result/" + rewards=np.load(output_path+"rewards.npy", ) + moving_average_rewards=np.load(output_path+"moving_average_rewards.npy",) + plot(rewards) + plot(moving_average_rewards,ylabel='moving_average_rewards') diff --git a/codes/dqn/result/moving_average_rewards.npy b/codes/dqn/result/moving_average_rewards.npy new file mode 100644 index 0000000000000000000000000000000000000000..b0e2a931f467248c4f3d76ed25c6c1e068314e7e GIT binary patch literal 1728 zcmbWr`CrqA0mgBhR40cJaI~_5DFwnMM*unGcq)k|7!Xh}0V3r1CSSyIF9s1MDhQSv zESFfE94eAl5eZOHWR|&6vEo2EtOr&Ot%8J0Cv*D~_WtF0J)e@m(10M`3JsY?8cj?j zi;`%bRGOE>on}X+N#c`Ik_2&4@kwIhzkRDpO$Km{fmwEggnUl~0qB zolrz}mK*=s2@^K*94EpNTE=xYya@*+l$Ab=QQ3o&ea|mS#~ubx&W61nv_p}9w2OIx z9j=b#oU943#bBy%=jbgPocp>?eBd)1Y(Ho}>&dnTbuET)V4HqZ6?k5DVBIg&Y!0CS%BU6D5Cmn z3#cWmeM5h;!1>4&0cFV?y=~)KvTgSGL;Lu#h<+!;G-&R*H%P~?x2tz~Z*jp>a<;sB zvpeXvdI=3JUZ`E=d3{=wfu&Cr#Sd*55M&OmoaZp0C8wA)#xgOWD$p>#&qN+ip>au@ z3HsiYjF3SFdWv0j%L1AB?Jj%fcs~Q1;29{JN zGJ4%cJ7O5nb-(;rJ;g*FQS(E0I}_{F)*;VknTWE^6;<>x5zlo>PAFx=DdwWIJd=%I zixh?NwrsFh4&U*wWZ~wHg)Etv4dD~!R?RDH_+HZ1aXZOD)`r^MhZeVEp~dh>Xa9C= zJn`tOg<1{@zgM0yhzo?&)yg4sPY_1mCtToE1!0N3OkX$@3_-!=B{>m-TI1EMox{N> zaq7QORvrvZ!_Mf?HNlu1-S6!jx(igL%0$TtL+h#B7kv~Sd~P_IZ0_bFwj}lE!1G)* zX&w*RNbnHTdeKpDI2>|qSA*Ha2xMJz7|oYN;3qz%r&$<*UQcW1KiWk=rO>v&KNJpL zzV}>bVmOXU-1gtv$Ae7o`LRP0TpXj_xzNewVm_y>qS1?sB4M7lRK!J468)I0jSHpo zlB~6#3zNSe23|J)eRHx+WL6-=9KB}ywV7yTe^}Q-$>N{ z^?hN{y+}kC8=d<6Q$F5YJ&-F20J+Pw{9Bd~_gFeL?PWrk z4-ZD>j|*|8(drfFi4c!8wBr}jMGzWab6nIC!{URC`8Y?6jCgjJSrB|Vgn8=rDsG9W~o;|?OSM+g{{cI`71p~ml%w6sJK^xw4p z-mxsgu(|KGn}@|HUj5R~;i?$b{q14%UlJHHKPR=-C9r4Lrx##Gprc$#_sk?P@;YWI z;1PkxyQ2iD_7bGKdL`D#B-kyQAPQS0sL}~hub7d*;=%36DoZK87#a7N36-KX%G4z< zLyFGVSJIx>OJVDiV@BSVA}^Q~vVUBPih~WJSWOZq!hU#IVnV`5G3Dp(LZT<{)tU+x ziOS_{vp3-+Y7Z+_iLoS_eD7Z893av1U0iD8aS~t7v0pWpkjUZ}gl3;6QS9lGvF#j* zN$E*T-Ag21`t9_ZQIQCJG1lx|w^sjz5dXR*f0z<4gzxhWHWQ=K$WlzynJNXa z%U8WqR0xp2-tzrym=MnXW=66VA_zuIw@p@x@Xg{KomCcM{CjJ=PskZD{OcQH9lsD^ zl$E|j`9*-zt^`4MT{PU4pZR>7CIEfqGq=@VLNx8*T=tj{;>fzjoyM6WY>CP^B&LXA z_G7(ILxC8XBSIB>1p#Ksj75Qz!1UzXxXNw<^;yHBL?a0t78~oAqa|QOyRg^SN}zR( QWtAR8AZ)ZjYfwqxKW+ix9{>OV literal 0 HcmV?d00001 diff --git a/codes/dqn/result/moving_average_rewards.png b/codes/dqn/result/moving_average_rewards.png new file mode 100644 index 0000000000000000000000000000000000000000..f49d951739b189cf65e40cc355fa4ef1dd80bf87 GIT binary patch literal 31573 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 YkILDsD0b8b68Jf+aa=u9&En?&0;tB4qyPW_ literal 0 HcmV?d00001 diff --git a/codes/dqn/result/rewards.npy b/codes/dqn/result/rewards.npy new file mode 100644 index 0000000000000000000000000000000000000000..7f7e3f98ce471f925892a93964ec32b2193b5a04 GIT binary patch literal 1728 zcmd^<+e(5#6oseTp5iB>-$Fu)O2UijBo%2EbUtbMTR~)KbQ8h6LoeW?%%k`y9p+nx z144A$f3sL?@4fb(J)`f{gG%jW%)FS_w3&5pI_YwfmRiL$pQNpJ=eg5(ylQuv*_U2! zJan^9y?fVq%078+u29HN=aaYO&)>ND{z^9B0yqgS1$1lh0yqWEgT+XnfXheu(sRV~ zQJ!?wiK}jg`~;M*@|72(;>s7wUtGSz5k78*{u?0sa~56=X!ip8MnFgY0C&;10vg=| z`*!H^9q<+Ewy9ekuJ`mc>*$*S9o%1_t8bY&eQgcSIqex-dFs0#bbA!gpMvP_ggSIX zont?Sxy*gYGfhzZ5I_7)eK@Z!&U~8F($^eQkI&#-m7rVVgZZiR_<4Ar`?H+G#plg} zUqYVIeP7WBRNP*op9gfUfQG$kAO1GzJ^bs@e(LBR>|Nud{YBWn8IJeK*L%^s@a)wp zu0EPG^6f>sWzIfzI?umB{-+Y{1#V`;{vGebEJpXC_Z;na)ZSc~di}oR-_tLBM){A@ I{m(o70MaqFQ~&?~ literal 0 HcmV?d00001 diff --git a/codes/dqn/result/rewards.png b/codes/dqn/result/rewards.png new file mode 100644 index 0000000000000000000000000000000000000000..c92289687403a314df3b4a711240bc65f8c2fe34 GIT binary patch literal 49809 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

X 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 E4=ZKQB>(^b literal 0 HcmV?d00001 diff --git a/codes/dqn_cnn/dqn.py b/codes/dqn_cnn/dqn.py new file mode 100644 index 0000000..3da4f3e --- /dev/null +++ b/codes/dqn_cnn/dqn.py @@ -0,0 +1,107 @@ +import random +import math +import torch +import torch.optim as optim +import torch.nn.functional as F +from memory import ReplayBuffer +from model import CNN + + +class DQN: + def __init__(self, screen_height=0, screen_width=0, n_actions=0, gamma=0.999, epsilon_start=0.9, epsilon_end=0.05, epsilon_decay=200, memory_capacity=10000, batch_size=128, device="cpu"): + self.actions_count = 0 + self.n_actions = n_actions + self.device = device + self.gamma = gamma + self.epsilon = 0 + self.epsilon_start = epsilon_start + self.epsilon_end = epsilon_end + self.epsilon_decay = epsilon_decay + self.batch_size = batch_size + self.policy_net = CNN(screen_height, screen_width, + n_actions).to(self.device) + self.target_net = CNN(screen_height, screen_width, + n_actions).to(self.device) + self.target_net.load_state_dict(self.policy_net.state_dict()) + self.target_net.eval() # 不启用 BatchNormalization 和 Dropout + self.optimizer = optim.RMSprop(self.policy_net.parameters()) + self.loss = 0 + self.memory = ReplayBuffer(memory_capacity) + + + def select_action(self, state): + '''choose_action [summary] + Args: + state [torch tensor]: [description] + Returns: + actions [torch tensor]: [description] + ''' + sample = random.random() + self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \ + math.exp(-1. * self.actions_count / self.epsilon_decay) + self.actions_count += 1 + if sample > self.epsilon: + with torch.no_grad(): + # t.max(1) will return largest column value of each row. + # second column on max result is index of where max element was + # found, so we pick action with the larger expected reward. + + q_value = self.policy_net(state) # q_value比如tensor([[-0.2522, 0.3887]]) + action = q_value.max(1)[1].view(1, 1) # q_value最大对应的下标,注意该action是个张量,如tensor([1]) + return action + else: + return torch.tensor([[random.randrange(self.n_actions)]], device=self.device, dtype=torch.long) + + def update(self): + if len(self.memory) < self.batch_size: + return + transitions = self.memory.sample(self.batch_size) + # Transpose the batch (see https://stackoverflow.com/a/19343/3343043 for + # detailed explanation). This converts batch-array of Transitions + # to Transition of batch-arrays. + batch = self.memory.Transition(*zip(*transitions)) + + # Compute a mask of non-final states and concatenate the batch elements + # (a final state would've been the one after which simulation ended) + non_final_mask = torch.tensor(tuple(map(lambda s: s is not None, + batch.next_state)), device=self.device, dtype=torch.bool) + + non_final_next_states = torch.cat([s for s in batch.next_state + if s is not None]) + state_batch = torch.cat(batch.state) + action_batch = torch.cat(batch.action) + reward_batch = torch.cat(batch.reward) # tensor([1., 1.,...,]) + + + # Compute Q(s_t, a) - the model computes Q(s_t), then we select the + # columns of actions taken. These are the actions which would've been taken + # for each batch state according to policy_net + state_action_values = self.policy_net( + state_batch).gather(1, action_batch) #tensor([[ 1.1217],...,[ 0.8314]]) + + # Compute V(s_{t+1}) for all next states. + # Expected values of actions for non_final_next_states are computed based + # on the "older" target_net; selecting their best reward with max(1)[0]. + # This is merged based on the mask, such that we'll have either the expected + # state value or 0 in case the state was final. + next_state_values = torch.zeros(self.batch_size, device=self.device) + + next_state_values[non_final_mask] = self.target_net( + non_final_next_states).max(1)[0].detach() + + # Compute the expected Q values + expected_state_action_values = (next_state_values * self.gamma) + reward_batch # tensor([0.9685, 0.9683,...,]) + + # Compute Huber loss + self.loss = F.smooth_l1_loss( + state_action_values, expected_state_action_values.unsqueeze(1)) # .unsqueeze增加一个维度 + # Optimize the model + self.optimizer.zero_grad() # zero_grad clears old gradients from the last step (otherwise you’d just accumulate the gradients from all loss.backward() calls). + self.loss.backward() # loss.backward() computes the derivative of the loss w.r.t. the parameters (or anything requiring gradients) using backpropagation. + for param in self.policy_net.parameters(): # clip防止梯度爆炸 + param.grad.data.clamp_(-1, 1) + self.optimizer.step() # causes the optimizer to take a step based on the gradients of the parameters. + + +if __name__ == "__main__": + dqn = DQN() diff --git a/codes/dqn_cnn/main.py b/codes/dqn_cnn/main.py new file mode 100644 index 0000000..5cacee3 --- /dev/null +++ b/codes/dqn_cnn/main.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 10:01:09 +@LastEditor: John +@LastEditTime: 2020-06-13 00:24:31 +@Discription: +@Environment: python 3.7.7 +''' +''' +应该是没有收敛,但是pytorch官方教程的结果也差不多 +''' +import gym +import torch + +from screen_state import get_screen +from dqn import DQN +from plot import plot + +import argparse + +def get_args(): + '''模型建立好之后只需要在这里调参 + ''' + parser = argparse.ArgumentParser() + + parser.add_argument("--gamma", default=0.999, type=float) # q-learning中的gamma + parser.add_argument("--epsilon_start", default=0.9, type=float) # 基于贪心选择action对应的参数epsilon + parser.add_argument("--epsilon_end", default=0.05, type=float) + parser.add_argument("--epsilon_decay", default=200, type=float) + + parser.add_argument("--memory_capacity", default=10000, type=int,help="capacity of Replay Memory") + + parser.add_argument("--batch_size", default=128, type=int,help="batch size of memory sampling") + parser.add_argument("--max_episodes", default=100, type=int) + parser.add_argument("--max_steps", default=200, type=int) + parser.add_argument("--target_update", default=4, type=int,help="when(every default 10 eisodes) to update target net ") + config = parser.parse_args() + + return config + +if __name__ == "__main__": + + cfg = get_args() + # if gpu is to be used + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + # Get screen size so that we can initialize layers correctly based on shape + # returned from AI gym. Typical dimensions at this point are close to 3x40x90 + # which is the result of a clamped and down-scaled render buffer in get_screen(env,device) + env = gym.make('CartPole-v0').unwrapped + env.reset() + init_screen = get_screen(env, device) + _, _, screen_height, screen_width = init_screen.shape + # Get number of actions from gym action space + n_actions = env.action_space.n + agent = DQN(screen_height=screen_height, screen_width=screen_width, + n_actions=n_actions, device=device, gamma=cfg.gamma, epsilon_start=cfg.epsilon_start, epsilon_end=cfg.epsilon_end, epsilon_decay=cfg.epsilon_decay, memory_capacity=cfg.memory_capacity,batch_size=cfg.batch_size) + + rewards = [] + moving_average_rewards = [] + for i_episode in range(1,cfg.max_episodes+1): + # Initialize the environment and state + env.reset() + last_screen = get_screen(env, device) + current_screen = get_screen(env, device) + state = current_screen - last_screen + ep_reward = 0 + for t in range(1,cfg.max_steps+1): + # Select and perform an action + action = agent.select_action(state) + _, reward, done, _ = env.step(action.item()) + ep_reward += reward + reward = torch.tensor([reward], device=device) + # Observe new state + last_screen = current_screen + current_screen = get_screen(env, device) + + if done: break + next_state = current_screen - last_screen + + # Store the transition in memory + agent.memory.push(state, action, next_state, reward) + + # Move to the next state + state = next_state + + # Perform one step of the optimization (on the target network) + agent.update() + + # Update the target network, copying all weights and biases in DQN + if i_episode % cfg.target_update == 0: + agent.target_net.load_state_dict(agent.policy_net.state_dict()) + print('Episode:', i_episode, ' Reward: %i' %int(ep_reward), 'Explore: %.2f' % agent.epsilon) + rewards.append(ep_reward) + if i_episode == 1: + moving_average_rewards.append(ep_reward) + else: + moving_average_rewards.append( + 0.9*moving_average_rewards[-1]+0.1*ep_reward) + + import os + import numpy as np + output_path = os.path.dirname(__file__)+"/result/" + if not os.path.exists(output_path): + os.mkdir(output_path) + np.save(output_path+"rewards.npy", rewards) + np.save(output_path+"moving_average_rewards.npy", moving_average_rewards) + print('Complete!') + plot(rewards) + plot(moving_average_rewards,ylabel="moving_average_rewards") + + diff --git a/codes/dqn_cnn/memory.py b/codes/dqn_cnn/memory.py new file mode 100644 index 0000000..4b9c59c --- /dev/null +++ b/codes/dqn_cnn/memory.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 09:42:44 +@LastEditor: John +@LastEditTime: 2020-06-11 15:50:33 +@Discription: +@Environment: python 3.7.7 +''' +from collections import namedtuple +import random + + + +class ReplayBuffer(object): + + def __init__(self, capacity): + self.capacity = capacity + self.buffer = [] + self.position = 0 + self.Transition = namedtuple('Transition', + ('state', 'action', 'next_state', 'reward')) + + def push(self, *args): + """Saves a transition.""" + if len(self.buffer) < self.capacity: + self.buffer.append(None) + self.buffer[self.position] = self.Transition(*args) + self.position = (self.position + 1) % self.capacity + + def sample(self, batch_size): + return random.sample(self.buffer, batch_size) + + def __len__(self): + return len(self.buffer) diff --git a/codes/dqn_cnn/model.py b/codes/dqn_cnn/model.py new file mode 100644 index 0000000..71e67ca --- /dev/null +++ b/codes/dqn_cnn/model.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 12:18:12 +@LastEditor: John +@LastEditTime: 2020-06-11 17:23:45 +@Discription: +@Environment: python 3.7.7 +''' +import torch.nn as nn +import torch.nn.functional as F + +class CNN(nn.Module): + + def __init__(self, h, w, n_outputs): + super(CNN, self).__init__() + self.conv1 = nn.Conv2d(3, 16, kernel_size=5, stride=2) + self.bn1 = nn.BatchNorm2d(16) + self.conv2 = nn.Conv2d(16, 32, kernel_size=5, stride=2) + self.bn2 = nn.BatchNorm2d(32) + self.conv3 = nn.Conv2d(32, 32, kernel_size=5, stride=2) + self.bn3 = nn.BatchNorm2d(32) + + # Number of Linear input connections depends on output of conv2d layers + # and therefore the input image size, so compute it. + def conv2d_size_out(size, kernel_size = 5, stride = 2): + return (size - (kernel_size - 1) - 1) // stride + 1 + convw = conv2d_size_out(conv2d_size_out(conv2d_size_out(w))) + convh = conv2d_size_out(conv2d_size_out(conv2d_size_out(h))) + linear_input_size = convw * convh * 32 + self.head = nn.Linear(linear_input_size, n_outputs) + + # Called with either one element to determine next action, or a batch + # during optimization. Returns tensor([[left0exp,right0exp]...]). + def forward(self, x): + x = F.relu(self.bn1(self.conv1(x))) + x = F.relu(self.bn2(self.conv2(x))) + x = F.relu(self.bn3(self.conv3(x))) + return self.head(x.view(x.size(0), -1)) \ No newline at end of file diff --git a/codes/dqn_cnn/plot.py b/codes/dqn_cnn/plot.py new file mode 100644 index 0000000..2579f86 --- /dev/null +++ b/codes/dqn_cnn/plot.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 16:30:09 +@LastEditor: John +@LastEditTime: 2020-06-11 22:27:24 +@Discription: +@Environment: python 3.7.7 +''' +import matplotlib.pyplot as plt +import numpy as np +import os + +def plot(item,ylabel='rewards'): + plt.figure() + plt.plot(np.arange(len(item)), item) + plt.title(ylabel+' of CnnDQN') + plt.ylabel('rewards') + plt.xlabel('episodes') + + plt.savefig(os.path.dirname(__file__)+"/result/"+ylabel+".png") + plt.show() diff --git a/codes/dqn_cnn/result/moving_average_rewards.npy b/codes/dqn_cnn/result/moving_average_rewards.npy new file mode 100644 index 0000000000000000000000000000000000000000..a132de38fd5c115457a6731db578b070771b2bd6 GIT binary patch literal 528 zcmbWr>q}Ds9Eb6vw3v3WZ7`IWPD)PNXc}T=6aD_oLC8YH8ZkkJo>N3^awaXTmA(+9 z(g^WZ5QdkiFtdvcryE{y!>vh^Mi(LGF!u0 zss%P*$!hpqR;6Tlvrs1(O;u*0hWqDQ<9Q3W>6Wv`T5j|A;1(F^qRE*KYHVvo#;BN7L6 zm3BN{8OEK}X*h#USR;Oj7QSMO_7C!e5ULwK;pXpm$T7@A7VzR&tsA{p9ca5Tj6Q-m7Eez z?I6=DFXz=z?8B z?XEnUm*$h+x}S3GskHG{PG2e|#PuXmYjFa_LMha>wv&Q|+o@=)h literal 0 HcmV?d00001 diff --git a/codes/dqn_cnn/result/moving_average_rewards.png b/codes/dqn_cnn/result/moving_average_rewards.png new file mode 100644 index 0000000000000000000000000000000000000000..c2cf945ec33a4c11f6f7c15fc786b62e7116a0aa GIT binary patch literal 34944 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 literal 0 HcmV?d00001 diff --git a/codes/dqn_cnn/result/rewards.npy b/codes/dqn_cnn/result/rewards.npy new file mode 100644 index 0000000000000000000000000000000000000000..551e671ccc9994a3a9cd718b675d61d6e2adad5c GIT binary patch literal 528 zcmbV`p-V$i6vofMWLhv9ZV;}*3s+c>v9PJwlvjiafYi7d5-Hd*92eo6cc*I2&tU;ZU-b-?{{vI_f=hX^|AAiPy@GP$EvkI&&`bf} Rpxf2gzGG(FsB#X{&M!FPUn&3q literal 0 HcmV?d00001 diff --git a/codes/dqn_cnn/result/rewards.png b/codes/dqn_cnn/result/rewards.png new file mode 100644 index 0000000000000000000000000000000000000000..9cfbf4a2ddcb0309e4e822a40091eb485b1c4800 GIT binary patch literal 45288 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 literal 0 HcmV?d00001 diff --git a/codes/dqn_cnn/screen_state.py b/codes/dqn_cnn/screen_state.py new file mode 100644 index 0000000..402eead --- /dev/null +++ b/codes/dqn_cnn/screen_state.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# coding=utf-8 +''' +@Author: John +@Email: johnjim0816@gmail.com +@Date: 2020-06-11 10:02:35 +@LastEditor: John +@LastEditTime: 2020-06-11 16:57:34 +@Discription: +@Environment: python 3.7.7 +''' + +import numpy as np +import torch +import torchvision.transforms as T +from PIL import Image + +resize = T.Compose([T.ToPILImage(), + T.Resize(40, interpolation=Image.CUBIC), + T.ToTensor()]) + + +def get_cart_location(env,screen_width): + world_width = env.x_threshold * 2 + scale = screen_width / world_width + return int(env.state[0] * scale + screen_width / 2.0) # MIDDLE OF CART + +def get_screen(env,device): + # Returned screen requested by gym is 400x600x3, but is sometimes larger + # such as 800x1200x3. Transpose it into torch order (CHW). + screen = env.render(mode='rgb_array').transpose((2, 0, 1)) + # Cart is in the lower half, so strip off the top and bottom of the screen + _, screen_height, screen_width = screen.shape + screen = screen[:, int(screen_height*0.4):int(screen_height * 0.8)] + view_width = int(screen_width * 0.6) + cart_location = get_cart_location(env,screen_width) + if cart_location < view_width // 2: + slice_range = slice(view_width) + elif cart_location > (screen_width - view_width // 2): + slice_range = slice(-view_width, None) + else: + slice_range = slice(cart_location - view_width // 2, + cart_location + view_width // 2) + # Strip off the edges, so that we have a square image centered on a cart + screen = screen[:, :, slice_range] + # Convert to float, rescale, convert to torch tensor + # (this doesn't require a copy) + screen = np.ascontiguousarray(screen, dtype=np.float32) / 255 + screen = torch.from_numpy(screen) + # Resize, and add a batch dimension (BCHW) + return resize(screen).unsqueeze(0).to(device) + +if __name__ == "__main__": + + import gym + env = gym.make('CartPole-v0').unwrapped + # if gpu is to be used + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + env.reset() + import matplotlib.pyplot as plt + + plt.figure() + plt.imshow(get_screen(env,device).cpu().squeeze(0).permute(1, 2, 0).numpy(), + interpolation='none') + plt.title('Example extracted screen') + plt.show() \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index faa2732..bcc257f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -29,6 +29,7 @@ ## 主要贡献者 - [@qiwang067](https://github.com/qiwang067) +- [@JohnJim0816](https://github.com/JohnJim0816) ## 关注我们 diff --git a/docs/chapter2/chapter2.md b/docs/chapter2/chapter2.md index af5badb..430f1ff 100644 --- a/docs/chapter2/chapter2.md +++ b/docs/chapter2/chapter2.md @@ -10,7 +10,7 @@ 强化学习的三个重要的要素:状态、动作和奖励。强化学习智能体跟环境是一步一步交互的,就是我先观察一下状态,然后再输入动作。再观察一下状态,再输出动作,拿到这些 reward 。它是一个跟时间相关的一个序列决策的问题。 -举个例子,在 $t-1$ 时刻,我看到了熊对我招手,那我下意识的可能输出的动作就是我赶紧跑路。熊看到了有人跑了,可能就觉得发现猎物,开始发动攻击。而在 $t$ 时刻的话,我如果选择装死的动作,可能熊咬了咬我那个摔了几下就发现就觉得挺无趣的,可能会走开。这个时候,我再跑路的话可能就跑路成功了,就是这样子的一个序列决策的过程。 +举个例子,在 $t-1$ 时刻,我看到了熊对我招手,那我下意识的可能输出的动作就是赶紧跑路。熊看到了有人跑了,可能就觉得发现猎物,开始发动攻击。而在 $t$ 时刻的话,我如果选择装死的动作,可能熊咬了咬我那个摔了几下就发现就觉得挺无趣的,可能会走开。这个时候,我再跑路的话可能就跑路成功了,就是这样子的一个序列决策的过程。 当然在输出每一个动作之前,其实你都是可以选择不同的动作。比如说在 $t$ 时刻,我选择跑路的时候,熊已经追上来了,如果说 $t$ 时刻,我没有选择装死,而我是选择跑路的话,这个时候熊已经追上了,那这个时候,其实我有两种情况转移到不同的状态去,就我有一定的概率可以逃跑成功,也有很大的概率我会逃跑失败。那我们就用状态转移概率 $p\left[s_{t+1}, r_{t} \mid s_{t}, a_{t}\right]$ 来表述说在 $s_t$ 的状态选择了 $a_t$ 的动作的时候,转移到 $s_{t+1}$ ,而且拿到 $r_t$ 的概率是多少。 @@ -103,7 +103,7 @@ $$ ![](img/2.14.png) -这种强化方式其实在数学上面一行公式就表达出来了。这种更新的方式叫做`时序差分(Temporal Difference)`。这个公式它想要表达就是我可以拿下一步的 Q 值 $Q(S_{t+_1},A_{t+1})$ 来更新我这一步的 Q 值 $Q(S_t,A_t)$ 。 +这种强化方式其实在数学上面一行公式就表达出来了。这种更新的方式叫做`时序差分(Temporal Difference)`。这个公式就是说可以拿下一步的 Q 值 $Q(S_{t+_1},A_{t+1})$ 来更新我这一步的 Q 值 $Q(S_t,A_t)$ 。 为了理解这个公式,如图所示,我们先把 $R_{t+1}+\gamma Q\left(S_{t+1}, A_{t+1}\right.)$ 当作是一个目标值,就是 $Q(S_t,A_t)$ 想要去逼近的一个目标值。我们想要计算的就是这个 $Q(S_t,A_t)$ 。因为最开始 Q 值都是随机初始化或者是初始化为零。它需要不断的去逼近它理想中真实的Q 值,我们就叫 target 。Target 就是未来收益的总和大概有多少,而且是带衰减的那个。 @@ -176,11 +176,14 @@ $$ ![](img/2.19.png) -我们再仔细地对比一下两个更新公式,它们俩的更新公式都是一样的。区别只在 target 计算的这一部分。Sarsa 是 $R_{t+1}+\gamma Q(S_{t+1}, A_{t+1})$ ,Q-learning 是$R_{t+1}+\gamma \underset{a}{\max} Q\left(S_{t+1}, a\right)$ 。 +Sarsa 和 Q-learning 的更新公式都是一样的,区别只在 target 计算的这一部分, -Sarsa 实际上都是用自己的策略产生了 S,A,R,S',A' 这一条轨迹。然后拿着 $Q(S_{t+1},A_{t+1})$ 去更新原本的Q值 $Q(S_t,A_t)$。 但是 Q-learning 并不需要知道,我实际上选择哪一个 action ,它默认下一个动作就是 Q 最大的那个动作。所以它知道实际上 behavior policy 可能会有 10% 的概率去选择别的动作,但是 Q-learning 并不担心受到探索的影响,它默认了就按照最优的策略来去优化我的目标策略,所以它可以更大胆地去寻找最优的路径,它其实会表现的比 Sarsa 大胆非常多。 +* Sarsa 是 $R_{t+1}+\gamma Q(S_{t+1}, A_{t+1})$ ; +* Q-learning 是$R_{t+1}+\gamma \underset{a}{\max} Q\left(S_{t+1}, a\right)$ 。 -然后Q-learning 的这个逐步的一个拆解的话,跟Sarsa 唯一一点不一样就是我并不需要提前知道我 $A_2$ ,我就能更新 $Q(S_1,A_1)$ 。在训练一个 episode 这个流程图当中,Q-leanring 在 learn 之前它也不需要去拿到 next action A',它只需要前面四个 $(S,A,R,S')$也就可以了。这一点就是跟 Sarsa 有一个很明显的区别。这边我们给出[ Q-learning 的 Python实现](https://github.com/datawhalechina/leedeeprl-notes/tree/master/docs/code/Q-learning)。 +Sarsa 实际上都是用自己的策略产生了 S,A,R,S',A' 这一条轨迹。然后拿着 $Q(S_{t+1},A_{t+1})$ 去更新原本的 Q 值 $Q(S_t,A_t)$。 但是 Q-learning 并不需要知道,我实际上选择哪一个 action ,它默认下一个动作就是 Q 最大的那个动作。Q-learning 知道实际上 behavior policy 可能会有 10% 的概率去选择别的动作,但是 Q-learning 并不担心受到探索的影响,它默认了就按照最优的策略来去优化我的目标策略,所以它可以更大胆地去寻找最优的路径,它其实会表现的比 Sarsa 大胆非常多。 + +然后 Q-learning 的这个逐步的一个拆解的话,跟 Sarsa 唯一一点不一样就是我并不需要提前知道我 $A_2$ ,我就能更新 $Q(S_1,A_1)$ 。在训练一个 episode 这个流程图当中,Q-learning 在 learn 之前它也不需要去拿到 next action A',它只需要前面四个 $(S,A,R,S')$也就可以了,这一点就是跟 Sarsa 有一个很明显的区别。这边我们给出[ Q-learning 的 Python实现](https://github.com/datawhalechina/leedeeprl-notes/tree/master/docs/code/Q-learning)。 ### Q-function Bellman Equation @@ -195,7 +198,7 @@ $$ >Bellman Equation 就是当前状态与未来状态的迭代关系,表示当前状态的值函数可以通过下个状态的值函数来计算。Bellman Equation 因其提出者、动态规划创始人 Richard Bellman 而得名 ,也 叫作“动态规划方程”。 -从另一方面考虑,在计算 $t$ 时刻的动作价值 $Q^{\pi}(s_t,a_t)$ 时,需要知道在 $t$、$t+1$、$t+2 \cdots \cdots$ 时刻的奖励,这样就不仅需要知道某一状态的所有可能出现的后续状态以及对应的奖励值,还要进行全宽度的回溯来更新状态的价值。这种方法无法在状态转移函数未知或者大规模问题中使用。因此,Q- learning 采用了浅层的时序差分采样学习,在计算累积奖励时,基于当前策略 $\pi$ 预测接下来发生的 $n$ 步动作($n$ 可以取 1 到 $+\infty$)并计算其奖励值。 +从另一方面考虑,在计算 $t$ 时刻的动作价值 $Q^{\pi}(s_t,a_t)$ 时,需要知道在 $t$、$t+1$、$t+2 \cdots \cdots$ 时刻的奖励,这样就不仅需要知道某一状态的所有可能出现的后续状态以及对应的奖励值,还要进行全宽度的回溯来更新状态的价值。这种方法无法在状态转移函数未知或者大规模问题中使用。因此,Q-learning 采用了浅层的时序差分采样学习,在计算累积奖励时,基于当前策略 $\pi$ 预测接下来发生的 $n$ 步动作($n$ 可以取 1 到 $+\infty$)并计算其奖励值。 具体来说,假设在状态 $s_t$ 下选择了动作 $a_t$,并得到了奖励 $r_t$ ,此时状态转移到 $s_{t+1}$,如果在此状态下根据同样的策略选择了动作 $a_{t+1}$ ,则 $Q^{\pi}(s_t,a_t)$ 可以表示为 $$ diff --git a/docs/chapter3/chapter3.md b/docs/chapter3/chapter3.md index 3fbfaa6..bb12533 100644 --- a/docs/chapter3/chapter3.md +++ b/docs/chapter3/chapter3.md @@ -235,6 +235,8 @@ $$ Advantage function 的意义就是,假设我们在某一个 state $s_t$ 执行某一个 action $a_t$,相较于其他可能的 action,它有多好。它在意的不是一个绝对的好,而是相对的好,即`相对优势(relative advantage)`。因为会减掉一个 b,减掉一个 baseline, 所以这个东西是相对的好,不是绝对的好。 $A^{\theta}\left(s_{t}, a_{t}\right)$ 通常可以是由一个 network estimate 出来的,这个 network 叫做 critic。 + + ## References * [Intro to Reinforcement Learning (强化学习纲要)](https://github.com/zhoubolei/introRL) diff --git a/docs/chapter4/chapter4.md b/docs/chapter4/chapter4.md index 1afd00f..dea583e 100644 --- a/docs/chapter4/chapter4.md +++ b/docs/chapter4/chapter4.md @@ -168,7 +168,7 @@ KL divergence 到底指的是什么?这边我是直接把 KL divergence 当做 ![](img/4.9.png) -在PPO 的paper 里面还有一个 `adaptive KL divergence`,这边会遇到一个问题就是 $\beta$ 要设多少,它就跟那个regularization 一样。regularization 前面也要乘一个weight,所以这个 KL divergence 前面也要乘一个 weight,但 $\beta$ 要设多少呢?所以有个动态调整 $\beta$ 的方法。在这个方法里面呢,你先设一个 KL divergence,你可以接受的最大值。然后假设你发现说你 optimize 完这个式子以后,KL divergence 的项太大,那就代表说后面这个 penalize 的 term 没有发挥作用,那就把 $\beta$ 调大。那另外你定一个 KL divergence 的最小值。如果发现 optimize 完上面这个式子以后,KL divergence 比最小值还要小,那代表后面这一项的效果太强了,你怕他只弄后面这一项,那$\theta$ 跟$\theta^k$ 都一样,这不是你要的,所以你这个时候你叫要减少 $\beta$。所以 $\beta$ 是可以动态调整的。这个叫做 adaptive KL penalty。 +在PPO 的paper 里面还有一个 `adaptive KL divergence`,这边会遇到一个问题就是 $\beta$ 要设多少,它就跟那个regularization 一样。regularization 前面也要乘一个weight,所以这个 KL divergence 前面也要乘一个 weight,但 $\beta$ 要设多少呢?所以有个动态调整 $\beta$ 的方法。在这个方法里面呢,你先设一个 KL divergence,你可以接受的最大值。然后假设你发现说你 optimize 完这个式子以后,KL divergence 的项太大,那就代表说后面这个 penalize 的 term 没有发挥作用,那就把 $\beta$ 调大。那另外你定一个 KL divergence 的最小值。如果发现 optimize 完上面这个式子以后,KL divergence 比最小值还要小,那代表后面这一项的效果太强了,你怕他只弄后面这一项,那 $\theta$ 跟 $\theta^k$ 都一样,这不是你要的,所以你这个时候你叫要减少 $\beta$。所以 $\beta$ 是可以动态调整的。这个叫做 adaptive KL penalty。 ![](img/4.10.png)