例子的环境是一个一维世界, 在世界的右边有宝藏, 探索者只要得到宝藏尝到了甜头, 然后以后就记住了得到宝藏的方法, 这就是他用强化学习所学习到的行为。
#先定义qtable 再定义如何去选择行为,再不断地更新
#表格是表示寻宝者在每一个位置的选择的概率
import numpy as np
import pandas as pd
import time
np.random.seed(2) #产生伪随机数列 每次产生都是一样的 #seed( ) 用于指定随机数生成时所用算法开始的整数值,如果使用相同的seed( )值,则每次生成的随即数都相同,如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同。
N_STATES:代表有多少个state,如下图所示,在这个小例子中,它代表的是冒险者(图中的O)所能到达的位置,一共有6个。
ACTIONS:冒险者所能采取的动作,即向左(left)或向右(right)。
EPSILON:贪婪度,实际上这是一个用来控制随机探索概率的。什么意思?就是说在每次选择动作之前,都会获得一个随机的概率(这个概率大于0小于1),然后程序会用它和EPSILON进行一个比较,当这个概率小于EPSILON时,采用当前state下值最大的动作(也就是我们学习到的值),否则,随机选择一个动作。
ALPHA:学习率,个人理解是确定将每次学到的值保留多少的变量,比如说这一次学到了100,但我的学习率为0.1,那么就只保留100*0.1=10
GAMMA:奖励递减值,这个值会导致离terminal越远,获得的值越小。
MAX_EPISODES:最大训练轮次。
#设置初始参数
N_STATES = 6 # 一维时间的宽度 N_STATES:代表有多少个state,如下图所示,在这个小例子中,它代表的是冒险者(图中的O)所能到达的位置,一共有6个。
ACTIONS = ['left','right'] #设置行动为向左走还是向右走
EPSILON = 0.9 #贪婪度 greedy 实际上这是一个用来控制随机探索概率的
#EPSILON = 0.9的意思是有0.9的概率按照Q的最大值选择action,有0.1的概率随机选择action,以引入变化。
ALPHA = 0.1 #学习率
GAMMA = 0.9 #奖励递减值 这个值会导致离terminal越远,获得的值越小。
MAX_EPISODES = 13 #最大回合数
FRESH_TIME = 0.01 #移动间隔时间
#建立Q_Table
#q_table的 index 是所有对应的state(探索者位置),
#columns 是对应的action(探索者行为)。
def build_q_table(n_ststes,actions):
table = pd.DataFrame(
np.zeros((n_ststes,len(actions))), #q_table 初始全为0 n_states行 len(actions)列 用法:zeros(shape, dtype=float,order=‘C’) 返回:返回来一个给定形状和类型的用0填充的数组;
columns = actions, #columns对应的是行为名称
)
#print(table)
return table
#DataFrame 是pandans的一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型值)。
#print(build_q_table(N_STATES,ACTIONS))
#定义动作
接着定义探索者是如何挑选行为的. 这是我们引入epsilon greedy的概念.
因为在初始阶段, 随机的探索环境, 往往比固定的行为模式要好, 所以这也是累积经验的阶段,我们希望探索者不会那么贪婪(greedy).
所以EPSILON就是用来控制贪婪程度的值.EPSILON可以随着探索时间不断提升(越来越贪婪), 不过在这个例子中, 我们就固定成EPSILON = 0.9, 90% 的时间是选择最优策略, 10% 的时间来探索。
q_table.iloc[]
loc是基于label进行索引的(基于样本标签)
iloc是基于position进行索引的(基于位置)
print(df1.loc[:,[‘a’, ‘b’]])(输出所有行,以及a、b列)
df1.loc[:,0:2]这么写报错, 因为loc索引的是label,显然在df1的列的名字中没有叫0,1和2的。
print(df1.iloc[:,0:2])而不可写为print(df1.iloc[:,[‘a’, ‘b’]])
numpy.random.uniform(low=0.0, high=1.0, size=None)
从[low, high])中均匀取值,没有任何参数的话,是从[0, 1)
all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。
元素除了是 0、空、None、False 外都算 True。
a.any()==0语句是判断阵列中的所有元素是否都为0,当全部为0是,返回真,当有元素不为0时,返回假
a.all()==0语句是判断阵列中是否存在为0的元素,当存在0元素时,返回真,当所有元素都不为0,返回假
#在某个state地点,选择行为
def choose_action(state,q_table):
state_actions = q_table.iloc[state,:] # 索引 选出这个state的action值
if(np.random.uniform() > EPSILON) or ((state_actions ==0).all()): #非贪婪模式(随机模式) 全为0的时候随机选 #np.random.uniform()从0到1内均匀取值
action_name = np.random.choice(ACTIONS) #这里大于0.9为什么是百分之十的情况 ??
else:
action_name = state_actions.idxmax() #贪婪模式 #pandas Series 的 argmax 方法和 idxmax 方法用于获取 Series 的最大值的索引值
#这里是<0.9 就是百分之90的情况 这里使用argmax方法有错误,改成idxmax就可以运行了!!
return action_name #返回选择的动作
#环境反馈
'''
做出行为后, 环境也要给我们的行为一个反馈,
反馈出下个 state (S_) 和 在上个 state (S) 做出 action (A) 所得到的 reward (R).
这里定义的规则就是, 只有当o移动到了T, 探索者才会得到唯一的一个奖励, 奖励值 R=1, 其他情况都没有奖励:
'''
#这段代码不用细讲,其实就是只有判断S到达了terminal,R才有不为0的返回值。
def get_env_feedback(S,A):
if A == 'right':
if S == N_STATES-2:
S_ = 'terminal'
R = 1
else:
S_ = S+1
R = 0
else:
R = 0 #向左走远离目标,则奖励为0
if S == 0:
S_ = S #走到最左边了,只能为0
else:
S_ = S - 1
return S_, R
#更新环境
def update_env(S,episode,step_counter):
env_list = ['-']*(N_STATES -1) + ['T'] #'---------T' our environment
if S == 'terminal':
interaction = 'Episode %s:total_steps = %s' %(episode+1,step_counter)
print('\r{}'.format(interaction),end= '')
time.sleep(2)
print('\r ',end="")
else:
env_list[S] ='o'
interaction = ''.join(env_list)
print('\r{}'.format(interaction),end="")
time.sleep(FRESH_TIME)
``#创建主循环
def rl():
q_table = build_q_table(N_STATES,ACTIONS) #建立一个N_STATES行,ACTION列,初始值全为0的表格
for episode in range(MAX_EPISODES):
step_counter = 0 #:每一轮次探索者到达终点需要的步数
S = 0 #初始状态为0 把探索者放在最左边 是每一轮次都要初始化
is_terminated = False #用来判断是否到达终点的布尔值,为真时代表当前state位于终点
update_env(S,episode,step_counter) #更新一下环境
while not is_terminated: #没有到达终点则继续走
A = choose_action(S,q_table)
S_,R = get_env_feedback(S,A)
q_predict= q_table.loc[S,A] #索引出标签S,A
if S_ != 'terminal':
q_target = R + GAMMA *q_table.iloc[S_,:].max() #GAMMA奖励递减值 这个值会导致离terminal越远,获得的值越小。因为没有到达终点,所以要奖励减小
else:
q_target = R
is_terminated = True
q_table.loc[S,A]+= ALPHA *(q_target -q_predict) # 新的q值 ALPHA是阿尔法 ,误差值=真实值-估计值
S = S_ #进行下一个状态
update_env(S,episode,step_counter+1) #每一回合都更新一下环境
step_counter += 1
return q_table
if __name__ == "__main__":
q_table = rl()
print('\r\nQ-table:\n')
print(q_table)