1.基础

智能体(agent):可以是一个简单的算法,通常输入为state,输出为policy(规则);

状态集(states):为智能体的输入;

动作集(actions):智能体的动作,比如左右移动;

奖励(rewards):环境根据智能体的动作,反馈回来的一个奖惩信号,可以为正奖励也可以为负奖励;

环境(environment):接收智能体的动作action,回馈reward和state。

2.推导

Q-learning是强化学习中的一种算法,Q即为Q(steat,action)就是在某一时刻的s状态下(s∈S),采取动作action(action∈A)动作能够获得收益的期望,也就是行为值value。该算法的主要思想就是将State与Action构建成一张Q-table来存储Q值,然后根据Q值来选取能够获得最大的收益的动作。Q是一个列表,一般当矩阵看,当然实际中由于探索过程的发散,这个表将很大很大,因此需要将表做成神经网络来储存,也就是深度强化学习(DQN)。

新Q(s,a)=老Q+学习率*偏差

3.例子

首先你是一个生活在一维平面内的婴儿,也就是智能体agent,你饿了,想吃东西。但你妈站在距离你6米远的地方,你必须找到你妈才能吃到东西(即寻宝过程)。

你只能左右上下移动(这里简化为左右移动),每次只能移动一米,你的移动就是动作action,而你妈刚好站在你右边6米。你所处的位置就是你的输入states。

这时候开始找你妈,往左边移动了一米即你发生了action, 但是与你妈更远了,你妈大喊:“乖宝宝,怎么还不过来呀,你走错啦,真笨”;当你往右移动一米,你妈说:“真聪明”,这时候“真笨”和“真聪明”这两个词恰好你听懂了,放进了心里,也就是reward负奖励和正奖励。

最终你通过不断左右左右移动,来到了你妈这里并吃上了热乎的食物,整个过程就是训练你的过程,也就是训练agent的过程。

# -u---T u是你的位置,T是你的最终目标

import pandas as pd
import random
import time

#首先设置参数
want = 0.9 #设置你的渴望即贪婪率
efficiency = 0.1 #学习效率
reward_decrease = 0.8 #奖励递减值

# 定义你目前所处的状态(位置)和环境
states = range(6) #设置状态集0-6 即你距离你妈6个步长
actions = ['left','right'] #设置动作集,一维只有两个方向,即向左和向右
rewards = [0, 0, 0, 0, 0, 1] #设置奖励集, 即第6位时你爬到你妈那里时,才给你奖励

Q_table = pd.DataFrame(data=[[0 for _ in actions] for _ in states],index = states,columns = actions)# 创建一个表格
# DataFrame函数创建一个表格,index为行,这里用状态集赋值;columns为列,这里用动作集赋值;Q为某一时刻下状态state中采取动作action能获得收益的期望,即行为值


# 定义环境更新函数,实时更新且打印状态
def updata_environment(state): #
    global states #状态设为全局变量,可以整个环境内引用

    environment = list('-----T') #环境设为一个6字符长的字符串
    if state != states[-1]: #如果不在最后一个位置
       environment[state] = 'u' #确定你所处的位置
    print('\r{}'.format(''.join(environment)), end='')#打印

    time.sleep(0.1)#调用线程推迟执行该函数0.1S

 #你动作之后,定义下一状态函数
def get_next_state(state, action):
    global states
    # left,right,none = -1,+1,0
    if action == 'right' and state != states[-1]: #如果你不在最后一个位置,则向你妈移动一位
        next_state = state +1
    elif action == 'left' and state != states[0]: #如果你不在最开始的一个位置,则远离你妈移动一位(elif表示否则如果,如果if步骤执行成功,那么elif步骤就不会执行)
        next_state = state -1  #如果if和elif都判断失败,则执行else语句
    else:
        next_state = state #否则+0,就是你没动的意思
    return next_state #把下一状态值返回带出

#定义当前状态下合法的动作集合函数
def get_vaild_actions(state):
    global actions

    vaild_actions = set(actions)
    if state == states[-1]: # 如果你在最后一个位置
        vaild_actions -= set(['right'])  #则不能再向右了
    if state == states[0]: #如果你在最初的位置
        vaild_actions -= set(['left'])  #则不能再向左了
    return list(vaild_actions) #把当前状态值返回带出为一个列表格式

for i in range(13):  #i在0-13内依次取值,这里的i是episode,即从action开始到结束的一个过程
    current_state = 0 #设置Q估计表内的状态位置为0
    # current_state = random.choice(states)
    updata_environment(current_state) #与绑定环境相关
    total_steps = 0

    while current_state != states[-1]:# 创建一个循环,直到你到达最后一个位置,这里是重复状态动作的执行
        if (random.uniform(0,1) > want) or ((Q_table.loc[current_state] == 0).all()): #random.uniform(0,1)表示在0-1内随机生成一个随机数,loc通过行/列标签索引到状态矩阵,(iloc通过行/列号索引矩阵这里没用到),all()表示索引到的状态矩阵与0的比对结果再作一次与运算
            current_action = random.choice(get_vaild_actions(current_state)) #random.choice可以从定义()里随机选取内容,并将选取结果放入赋值中返回
            # 该if语句意思为:如果你的渴望(贪婪)小于这个随机数或者索引到的估计状态为0,则你目前探索到的状态是正确的行动
        else:
            current_action = Q_table.loc[current_state].idxmax()#否则利用你的渴望逼近正确的行动,idmax()表示索引最大值

        next_state = get_next_state(current_state,current_action) #调用你下一动作后的状态函数,与估计到的正确状态和动作绑定
        next_state_Q_values = Q_table.loc[next_state,get_vaild_actions(next_state)] # 得到现实Q
        Q_table.loc[current_state, current_action] += efficiency*(rewards[next_state] + reward_decrease*next_state_Q_values.max() - Q_table.loc[current_state,current_action]) #根据贝尔曼方程更新Q,Q为某一时刻下状态state中采取动作action能获得收益的期望,Q_table.loc[current_state,current_action]为估计的Q
        current_state = next_state
        updata_environment(current_state) #更新环境
        total_steps += 1 #总步骤加1

    print('\rEpisode {}: total_steps = {}'.format(i, total_steps), end='')
    time.sleep(2)
    print('\r',end='')

print('\nQ_table:')
print(Q_table)