【RL】异策略算法Q-Learning寻宝藏小例子

介绍

例子的环境是一个一维世界, 在世界的右边有宝藏, 探索者只要得到宝藏尝到了甜头, 然后以后就记住了得到宝藏的方法, 这就是他用强化学习所学习到的行为。

#先定义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)


你可能感兴趣的:(实战,算法,python,强化学习)