1.本文实现的是一个一维探索者寻找宝藏的小游戏
莫烦python 大佬讲解Q-Learning以及实现的视频链接
视频:
【莫烦Python】强化学习 Reinforcement Learning_哔哩哔哩_bilibili
代码:
2.示例效果:
show_result
3.Q-Learning代码学习(修改了pandas已弃用的函数,增加了详细注释)
###########################################################
#######Q-Learning 是一种离线学习的Model-Free 方法##############
# 这种使用贪心算法进行随机探索更新的方法只适用于有限离散状态和动作空间 #
###########################################################
import numpy as np
import pandas as pd
import time
# 设置随机数种子
# 用于生成伪随机数
# 放在这里保证每一次运行程序随机过程相同,生成的随机数和UP主示例结果相同
# 可以不用设置
# np.random.seed(n)
# https://zhuanlan.zhihu.com/p/266472620
np.random.seed(3)
# 状态数,一维状态空间的长度
N_STATES = 6
# 动作空间
ACTIONS = ['left', 'right']
# 贪心算法参数(随机生成)
EPSILON = 0.9
# 学习率
ALPHA = 0.1
# 衰减因子
GAMMA = 0.9
# 训练总轮数
MAX_EPISODES = 10
# 每次环境更新用时
FRESH_TIME = 0.2
##########建立Q-Table函数####################
##########参数 状态数,动作#################
def build_q_table(n_states, actions):
# 生成DataFrame数据类型,保存Q值
# pd.DataFrame()
# DataFrame是Python中Pandas库中的一种数据结构,它类似excel,是一种二维表。
# https://www.cnblogs.com/andrew-address/p/13040035.html
table = pd.DataFrame(
# 初始化 行数为n_states,列数为动作数len(actions)的DataFrame,数据为全零
np.zeros((n_states, len(actions))),
# 列名为动作名
columns=actions,
)
# 显示
# "{}".format()方法
# https://www.itzixishi.com/course/python/att-string-format.html
print('Q-Table')
print('\n{}'.format(table))
return table
# Q-Table 初始化示例
# q_table=build_q_table(N_STATES,ACTIONS)
# left right
# 0 0.0 0.0
# 1 0.0 0.0
# 2 0.0 0.0
# 3 0.0 0.0
# 4 0.0 0.0
# 5 0.0 0.0
###########动作选择函数##################
###########输入参数:当前状态和q_table####
def choose_action(state, q_table):
# 从q_table 获取当前状态可以选择的动作的Q值
# DataFrame.iloc()
# https://blog.csdn.net/bluishglc/article/details/121791352
state_actions = q_table.iloc[state, :]
########贪心算法实现#############
# 从0-1的均匀分布中生成随机数
# np.random.uniform()
# https://blog.csdn.net/u013920434/article/details/52507173
random_num = np.random.uniform()
# print('random_number{}'.format(random_num))
# 如果随机数大于EPSILON 0.9,或者状态对应动作的Q值全为0时,随机选择动作
if (random_num > EPSILON) or (state_actions.all() == 0):
# 随机选择动作的实现方法
# np.random.choice()
# https://blog.csdn.net/weixin_42462804/article/details/106122642
action_name = np.random.choice(ACTIONS)
else:
# 选择Q值最大的动作的索引,即'left'或者'right'
# pandas.DataFrame.idxmax()
action_name = state_actions.idxmax()
# 返回当前状态下选择的动作名
return action_name
###########环境反馈函数#################################
###########需要参数:当前状态和根据Q-Table选择的动作########
def get_env_feedback(S, A):
if A == 'right':
# 状态4即环境为 ---o-T 时,如果选择动作为 'right',则状态变为 'terminal'
if S == N_STATES - 2:
S_ = 'terminal'
# 给定奖励 1
R = 1
else:
# 状态+1,奖励0
S_ = S + 1
R = 0
else:
# 向左走,奖励为0
R = 0
# 初始状态向左走,保持初始状态
if S == 0:
S_ = S
# 非初始状态向左走,状态-1
else:
S_ = S - 1
# 返回下一个状态和奖励值
return S_, R
##############环境更新函数#####################################################
##############需要参数: 当前状态S,轮数episode以及每一轮进行到的步数step_counter#####
def update_env(S, episode, step_counter):
# 环境列表
env_list = ['-'] * (N_STATES - 1) + ['T']
# ['-', '-', '-', '-', '-', 'T']
if S == 'terminal':
# 'terminal'状态下输出训练episode和total_step
interaction = 'Episode %s: total _steps = %s ' % (episode + 1, step_counter)
print('\r{}'.format(interaction), end='')
# 延时显示,方便演示
time.sleep(2)
print('\r ', end='')
else:
# 状态S时,设置env_list[S] = 'o'
env_list[S] = 'o'
# 连接env_list为新的字符串,方便显示
# ''.join()
# https://blog.csdn.net/weixin_43969815/article/details/97142426
interaction = ''.join(env_list)
print('\r{}'.format(interaction), end='')
# 延时更新环境
time.sleep(FRESH_TIME)
#############强化学习算法实现函数#################
def rl():
# 初始化Q-Table
q_table = build_q_table(N_STATES, ACTIONS)
# 开始训练
for episode in range(MAX_EPISODES):
# 初始化step计数器为0
step_counter = 0
# 初始化状态为0
S = 0
# 初始化每一轮的结束标志符为False
is_terminated = False
# 更新环境
update_env(S, episode, step_counter)
while not is_terminated:
# 根据当前状态和Q-Table选择动作
A = choose_action(S, q_table)
# 给出根据当前状态和Q-Table选择动作后的新状态和返回值
S_, R = get_env_feedback(S, A)
# 根据Q-Table得到q_pred
q_predict = q_table.loc[S, A]
# 获取q_target
if S_ != 'terminal':
q_target = R + GAMMA * q_table.iloc[S_, :].max()
else:
q_target = R
is_terminated = True
q_table.loc[S, A] += ALPHA * (q_target - q_predict)
# 更新状态
S = S_
# 跟新环境
update_env(S, episode, step_counter + 1)
# step 计数器+1
step_counter += 1
return q_table
if __name__ == "__main__":
q_table = rl()
print('\r\nQ-table:\n', q_table)
文章出处登录后可见!
已经登录?立即刷新