24/8/15算法笔记 时序差分算法sarsa

  1. 在线学习:TD学习是一种在线学习算法,它可以在与环境交互的过程中逐步更新预测。

  2. 引导探索:TD学习算法使用之前的估计来引导对状态或状态-动作对的价值评估,这有助于在探索过程中减少不确定性。

  3. 时间差分更新

    • TD更新公式通常写作:V(St)←V(St)+α[Rt+1+γV(St+1)−V(St)]V(St​)←V(St​)+α[Rt+1​+γV(St+1​)−V(St​)]
    • 其中,VV 是状态价值函数,StSt​ 和 St+1St+1​ 分别是当前和下一个状态,Rt+1Rt+1​ 是在 St+1St+1​ 处获得的即时奖励,αα 是学习率,γγ 是折扣因子。
  4. TD(0):TD(0)是TD学习的一个特殊情况,它使用当前状态的估计值作为下一个状态的估计值,更新公式简化为:V(St)←V(St)+α[Rt+1−V(St)]V(St​)←V(St​)+α[Rt+1​−V(St​)]

  5. SARSA:状态-动作-奖励-状态-动作(State-Action-Reward-State-Action, SARSA)算法是TD学习的一种变体,它用于学习一个策略,同时更新状态-动作对的价值函数 QQ。

  6. Q-Learning:Q-Learning是另一种TD学习变体,它使用一个偏置策略来探索所有可能的动作,并更新状态-动作对的价值函数 QQ,目标是学习最优价值函数。

  7. 收敛性:在某些条件下,TD学习算法能够收敛到最优价值函数或最优策略。

  8. 应用:TD学习方法广泛应用于各种强化学习问题,包括游戏、机器人导航和控制等领域。

  9. 实现:TD学习可以很容易地实现,并与神经网络等函数逼近方法结合使用。

#获取一个格子的状态
def get_state(row,col):
    if row!=3:
        return 'ground'
    if row==3 and col==0:
        return 'ground'
    if row==3 and col==11:
        return 'terminal'
    return 'trap'
get_state(0,0)
def move(row,col,action):
    if get_state(row,col) in['trap','terminal']:
        return row,col,0
    if action ==0:
        row-=1
    if action==1:
        row+=1
    if action==2:
        col-=1
    if action==3:
        col+=1
    row = max(0,row)
    row = min(3,row)
    col = max(0,col)
    col = min(11,col)
    
    reward=-1
    if get_state(row,col) =='trap':
        reward-=100
    return row,col,reward
#初始化Q矩阵,用于评估每个动作的价值
import numpy as np
#初始化在每个格子里采取每个动作的分数,初始化都是0,因为没有任何的知识
Q = np.zeros([4,12,4])

Q.shape
(4, 12, 4)
#动作函数
import random
#根据状态选择一个动作
def get_action(row,col):
    #有小概率选择随机动作
    if random.random()<0.1:
        return random.choice(range(4))
    #否则选择分数最高的动作
    return Q[row,col].argmax()
get_action(0,0)
#算法核心
#更新分数,每次取决于当前的格子,当前的动作,下个格子,下个格子的动作
def get_update(row,col,action,reward,next_row,next_col,next_action):
    #计算target
    target = 0.9*Q[next_row,next_col,next_action]#用q矩阵来衡量
    target+=reward
    
    #计算value
    value = Q[row,col,action]
    
    #根据时序差分算法,当前state,action的分数 = 下一个state,action的分数*gamma+reward
    #此处是求两者的差,越接近0越好
    update = target-value
    
    #这个0.1相当于lr
    update*=0.1
    
    #更新当前状态和动作的分数
    return update
#在0,0向右走,得到-1,到达0,1,再次执行向右走
get_update(0,0,3,-1,0,1,3)
#训练,sarsa算法是在线学习算法
def train():
    for epoch in range(1500):
        #初始化当前位置
        row = random.choice(range(4))
        col = 0
        
        #初始化第一个动作
        action = get_action(row,col)
        
        #计算反馈的和,这个数字应该越大越好
        reward_sum=0   #衡量这个游戏玩的有多好
        
        #循环直到到达终点或者陷阱
        while get_state(row,col)not in ['terminal','trap']:
            
            #执行动作
            next_row,next_col,reward = move(row,col,action)
            reward_sum+=reward
            
            #求新位置的动作
            next_action = get_action(next_row,next_col)
            
            #更新分数
            update = get_update(row,col,actoin,reward,next_row,next_col,next_action)
            
            Q[row,col,action]+=update
            #更新当前位置
            row = next_row
            col = next_col
            action = next_action
        
        if epoch%150==0:
            print(epoch,reward_sum)
def show(row,col,action):
    graph=[
     '','0','0','0','0','0','0','0','0','0','0','0','0','0',
     '0','0','0','0','0','0','0','0','0','0','0','0','0','0',
     '0','0','0','0','0','0','0','0','0','2','2','2','2','2',   
     '2','2','2','2','2','1'
    ]
    action = {0:'上',1:'下',2:'左',3:'右'}[action]
    
    graph[row*12+col] = action
    
    graph=' '.join(graph)
    
    for i in range(0,4*12,12):
        print(graph[i:i+12])
        
show(1,1,0)
#测试函数
from IPython import display
import time

def test():
    #起点
    row = random.choice(range(4))
    col = 0
    
    #最多玩N步
    for _ in range(200):
        
        #获取当前状态,如果状态时终点或者陷阱
        if get_state(row,col)in ['trap','terminal']:
            break
        #选择最优动作
        action = Q[row,col].argmax()
        
        #打印这个动作
        display.clear_output(wait = True)
        time.sleep(0.1)
        show(row,col,action)
        
        #执行动作
        row,col,reward = move(row,col,action)
        
test()
for row in range(4):
    line=''
    for col in range(12):
        action = Q[row,col].argmax()
        action = {0:'上',1:'下',2:'左',3:'右'}[action]
        line+=action
    print(line)

Qlearning算法,sarsa算法的改进

#qlearning算法,在sarsa算法的改进
#算法核心
#更新分数,每次取决于当前的格子,当前的动作,下个格子,下个格子的动作
def get_update(row,col,action,reward,next_row,next_col,next_action):
    #计算target
    target = 0.9*Q[next_row,next_col,next_action].max()#改进#用q矩阵来衡量
    target+=reward
    
    #计算value
    value = Q[row,col,action]
    
    #根据时序差分算法,当前state,action的分数 = 下一个state,action的分数*gamma+reward
    #此处是求两者的差,越接近0越好
    update = target-value
    
    #这个0.1相当于lr
    update*=0.1
    
    #更新当前状态和动作的分数
    return update
#在0,0向右走,得到-1,到达0,1,再次执行向右走
get_update(0,0,3,-1,0,1,3)

N步sarsa算法

玩N步更新第一步参数

#获取一个格子的状态
def get_state(row,col):
    if row!=3:
        return 'ground'
    if row==3 and col==0:
        return 'ground'
    if row==3 and col==11:
        return 'terminal'
    return 'trap'
get_state(0,0)
#动作函数
import random
#根据状态选择一个动作
def get_action(row,col):
    #有小概率选择随机动作
    if random.random()<0.1:
        return random.choice(range(4))
    #否则选择分数最高的动作
    return Q[row,col].argmax()
get_action(0,0)
def move(row,col,action):
    if get_state(row,col) in['trap','terminal']:
        return row,col,0
    if action ==0:
        row-=1
    if action==1:
        row+=1
    if action==2:
        col-=1
    if action==3:
        col+=1
    row = max(0,row)
    row = min(3,row)
    col = max(0,col)
    col = min(11,col)
    
    reward=-1
    if get_state(row,col) =='trap':
        reward-=100
    return row,col,reward
#初始化q矩阵和3个list
import numpy as np

#初始化在每一个格子里采取每个动作的分数初始化都是0,因为没有任何的知识
Q = np.zeros([4,12,4])

#初始化3个list,用来存储状态动作,反馈的历史数据,因为后面要回溯这些数据
state_list = []
action_list=[]
reward_list=[]

Q.shape
#获取更新量的函数
#target时累加的
#获取5个时间步分别的分数
def get_update_list(next_row,next_col,next_action):
    #初始化的target是最后一个state和最后一个action的分数
    target = Q[next_row,next_col,next_action]
    
    #计算每一步的target
    #每一步的target等于下一步的target*0.9,再加上基本的reward
    #时间从后往前回溯,越以前的target会累加的信息越多
    #[4,3,2,1,0]
    target_list = []
    for i in range(5):
        row,col = state_list[i]
        action = action_list[i]
        value_list.append(Q[row,col,action])
        
    #计算每一步的更新量
    update_list = []
    for i in range(5):
        #根据时序差分算法,当前state,action的分数 = 下一个state,action的分数*gamma+reward
        #此处是求两者的差,越接近0越好
        update = target_list[i]-value_list[i]
        
        #这个0.1指lr学习率
        update*=0.1
        
        update_list.append(update)
        
    return update_list
#训练函数
def train():
    for epoch in range(1500):
        #初始化当前位置
        row =random.choice(range(4))
        col = 0
        #初始化第一个动作
        action = get_action(row,col)
        
        #计算反馈的和,这个数字一个越来越小
        reward_sum = 0
        
        #初始化3个列表
        state_list.clear()
        action_list.clear()
        reward_list.clear()
        
        #循环直到到达终点或陷阱
        while get_state(row,col)not in ['termianl','trap']:
            
            #执行动作
            next_row,next_col,reward = move(row,col,action)
            reward_sum+=reward
            
            #求新位置的动作
            next_action = get_action(next_row,next_col)
            
            #记录历史数据
            state_list.append([row,col])
            action_list.append([action])
            reward_list.append(reward)
            
            #积累到5步以后再开始更新参数
            if len(state_list)==5:
                #计算分数
                update_list = get_update_list(next_row,next_col,next_action)
                
                #只更新第一步的分数
                row,col = state_list[0]
                action = action_list[0]
                update = update_list[0]
                
                Q[row,col,action]+=update
                
                #移除第一步,这样再下一次循环时保持列表时5个元素
                state_list.pop(0)
                action_list.pop(0)
                reward_list.pop(0)
            #更新当前位置
            row = next_row
            col = next_col
            action = next_action
        #走到终点以后,更新剩下步数的update
        for i in range(len(state_list)):
            row,col = state_list[i]
            action = action_list[i]
            update =update_list[i]
            Q[row,col,action]+=update
            
        if epoch%100 ==0:
            print(epoch,reward_sum)

DynaQ算法

#获取一个格子的状态
def get_state(row,col):
    if row!=3:
        return 'ground'
    if row==3 and col==0:
        return 'ground'
    if row==3 and col==11:
        return 'terminal'
    return 'trap'
get_state(0,0)

def move(row,col,action):
    if get_state(row,col) in['trap','terminal']:
        return row,col,0
    if action ==0:
        row-=1
    if action==1:
        row+=1
    if action==2:
        col-=1
    if action==3:
        col+=1
    row = max(0,row)
    row = min(3,row)
    col = max(0,col)
    col = min(11,col)
    
    reward=-1
    if get_state(row,col) =='trap':
        reward-=100
    return row,col,reward
#动作函数
import random
#根据状态选择一个动作
def get_action(row,col):
    #有小概率选择随机动作
    if random.random()<0.1:
        return random.choice(range(4))
    #否则选择分数最高的动作
    return Q[row,col].argmax()
get_action(0,0)
#初始化Q矩阵和历史数据字典
import numpy as np

#初始化再每一个格子里采取每个动作的分数,初始化都是0,因为没有任何的知识
Q = np.zeros([4,12,4])

#保存历史数据,键是(row,col,action),值是(next_row,next_col,reward)
history = dict() #字典

Q.shape,history
((4, 12, 4), {})
#计算更新量函数,和qlearning函数一样
#更新分数,每次取决于当前的格子,当前的动作,下个格子,下个格子的动作
def get_update(row,col,action,reward,next_row,next_col,next_action):
    #计算target
    target = 0.9*Q[next_row,next_col,next_action]#用q矩阵来衡量
    target+=reward
    
    #计算value
    value = Q[row,col,action]
    
    #根据时序差分算法,当前state,action的分数 = 下一个state,action的分数*gamma+reward
    #此处是求两者的差,越接近0越好
    update = target-value
    
    #这个0.1相当于lr
    update*=0.1
    
    #更新当前状态和动作的分数
    return update
#在0,0向右走,得到-1,到达0,1,再次执行向右走
get_update(0,0,3,-1,0,1,3)
#离线学习函数
import random
def q_planning():
    #Qplanning循环,相当于是在反刍历史数据,随机取N个历史数据再进行离线学习
    for _ in range(20):
        #随机选择曾经遇到过的状态动作对
        row,col,action = random.choice(list(history.keys()))
        
        #再获取下一个状态和反馈
        next_row,next_col,reward = history[(row,col,action)]
        
        #计算分数
        update = get_update(row,col,action,reward,next_row,next_col)
        
        #更新分数
        Q[row,col,action]+=update
        
#训练,sarsa算法是在线学习算法
def train():
    for epoch in range(1500):
        #初始化当前位置
        row = random.choice(range(4))
        col = 0
        
        #初始化第一个动作
        action = get_action(row,col)
        
        #计算反馈的和,这个数字应该越大越好
        reward_sum=0   #衡量这个游戏玩的有多好
        
        #循环知道到达终点或者陷阱
        while get_state(row,col)not in ['terminal','trap']:
            
            #执行动作
            next_row,next_col,reward = move(row,col,action)
            reward_sum+=reward
            
            #求新位置的动作
            next_action = get_action(next_row,next_col)
            
            #更新分数
            update = get_update(row,col,actoin,reward,next_row,next_col,next_action)
            
            #将数据添加到模型中
            history [(row,col,action)] = next_row,next_col,reward
            
            #反刍历史数据,进行离线学习
            q_planning()

            #更新当前位置
            row = next_row
            col = next_col
            action = next_action
        
        if epoch%150==0:
            print(epoch,reward_sum)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值