24/8/17算法笔记 DDPG算法

深度确定性策略梯度(DDPG)算法是一种用于解决连续动作空间强化学习问题的算法。它结合了确定性策略梯度(DPG)和深度学习技术的优点,通过Actor-Critic框架进行策略和价值函数的近似表示。DDPG算法的关键组成部分包括经验回放缓冲区、Actor-Critic神经网络、探索噪声、目标网络以及软目标更新。

DDPG算法使用两个神经网络,分别作为Actor和Critic。Actor网络负责生成策略,即在给定状态下选择最佳动作,而Critic网络评估当前策略的表现,通过Q值来衡量。经验回放缓冲区存储了与环境交互过程中产生的转换数据,这些数据用于训练网络,打破样本之间的时间相关性,提高学习效率。

DDPG算法的一个关键特性是目标网络的使用,它通过缓慢更新目标网络的参数来增加学习过程的稳定性。软更新是通过将目标网络参数设置为目标网络参数加上一小部分主网络参数的变化来实现的。

探索噪声是DDPG算法中用于平衡探索与利用的另一个重要组成部分。通过在Actor网络输出的动作上添加噪声,鼓励智能体探索环境,这有助于发现更好的策略。

在实现DDPG算法时,需要定义Actor和Critic网络,初始化目标网络,并设置优化器。训练过程中,通过从经验回放缓冲区中采样数据来更新网络参数。更新过程包括计算目标Q值、当前Q值,并分别更新Critic和Actor网络。

import gym
from matplotlib import pyplot as plt
%matplotlib inline
#创建环境
env = gym.make('Pendulum-v1')
env.reset()

#打印游戏
def show():
    plt.imshow(env.render(mode='rgb_array'))
    plt.show()

action网络模型

import torch

class Model(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.sequential = torch.nn.Sequential(
            torch.nn.Linear(3,64),#第一层全连接层,将输入特征从3维映射到64维。
            torch.nn.ReLU(),     #ReLU激活函数,用于引入非线性。
            torch.nn.Linear(64,64), #第二层全连接层,将64维特征再次映射到64维。
            torch.nn.ReLU(),    #ReLU激活函数。
            torch.nn.Linear(64,1), #第三层全连接层,将64维特征映射到1维,即输出一个值。
            torch.nn.Tanh(), #Tanh激活函数,将输出值映射到-1到1之间。
        )
    def forward(self,state):  #是前向传播函数,它定义了如何计算网络的输出。在这里,它将输入 state 通过 self.sequential 进行处理,然后乘以2.0。
        return self.sequential(state)*2.0

model_action = Model()
model_action_next = Model()

model_action_next.load_state_dict(model_action.state_dict())
model_action(torch.randn(1,3))

value网络模型

model_value = torch.nn.Sequential(
    torch.nn.Linear(4,64),
    torch.nn.ReLU(),
    torch.nn.Linear(64,64),
    torch.nn.ReLU(),
    torch.nn.Linear(64,1),
)
model_value_next = torch.nn.Sequential(
    torch.nn.Linear(4,64),
    torch.nn.ReLU(),
    torch.nn.Linear(64,64),
    torch.nn.ReLU(),
    torch.nn.Linear(64,1),
)
model_value_next.load_state_dict(model_value.state_dict())
model_value(torch.randn(1,4))

动作函数

import random
import numpy as np
def get_action(state):
    state = torch.FloatTensor(state).reshape(1,3)
    action = model_action(state).item() #.item(): 这个方法通常用于将一个张量(tensor)转换成一个标准的Python数值。在PyTorch中,模型的输出通常是一个张量。如果你想要获取这个张量中的单个值,可以使用.item()方法。
    #给动作添加噪声,增加探索
    action +=random.normalvariate(mu=0,sigma=0.01)#高斯随机噪声
    return action

更新样本池函数,准备离线学习

#样本池
datas = []

#向样本池中添加N条数据,删除M条最古老的数据
def update_data():
    #初始化游戏
    state = env.reset()
    
    #玩到游戏结束为止
    over = False
    while not over:
        #根据当前状态得到一个动作
        action = get_action(state)
        
        #执行动作,得到反馈
        next_state,reward,over,_ = env.step([action])
        
        #记录数据样本
        datas.append((states,action,reward,next_state,over))
        
        #更新游戏状态,开始下一个当作
        state = next_state
    #数据上限,超出时从最古老的开始删除
    while len(datas)>10000:
        datas.pop(0)
        

env.step(action) 是一个常用方法,用于执行给定的动作 action 并与之环境交互。

数据采样函数

#获取一批数据样本
def get_sample():
    samples = random.sample(datas,64)
    #[b,4]
    state = torch.FloatTensor([i[0]for i in samples]).reshape(-1,3)
    #[b,1]
    action = torch.LongTensor([i[1]for i in samples]).reshape(-1,1)
    #[b,1]
    reward = torch.FloatTensor([i[2]for i in samples]).reshape(-1,1)
    #[b,4]
    next_state = torch.FloatTensor([i[3]for i in samples]).reshape(-1,3)
    #[b,1]
    over = torch.LongTensor([i[4]for i in samples]).reshape(-1,1)

    return state,action,reward,next_state,over

state,action,reward,next_state,over=get_sample()

state[:5],action[:5],reward[:5],next_state[:5],over[:5]

这些数据通常用于训练强化学习模型,其中状态 statenext_state 被用来输入到价值函数或策略网络中,action 是模型选择的动作,reward 是环境对动作的反馈,over 表示游戏是否结束,通常用于确定奖励的折扣因子。

测试函数

from IPython import display

def test(play):
    #初始化游戏
    state = env.reset()#重置环境状态
    
    #记录反馈值的和,这个值越大越好
    reward_sum= 0
    
    #玩到游戏结束为止
    over =False
    while not over:
        #根据当前状态得到一个动作
        action = get_action(state)
        
        #执行动作,得到反馈
        staet,reward,over,_=env.step(action)
        reward_sum+=reward
        
        #打印动画
        if play and random.random()<0.2: #用于清除先前在输出区域的显示内容
            display.clear_output(wait=True)  #wait:设置为 True 时,clear_output 将等待所有异步输出完成之后再清除输出区域。这可以确保在清除之前所有输出都已经显示。    
            show()
    return  reward_sum
def get_value(state,action):
    #直接评估综合了state和action的value
    input = torch.cat([state,action],dim=1) #torch.cat 函数用于连接多个张量,dim 参数指定了沿着哪个维度进行连接。
    
    return model_value(input)

def get_target(next_state,reward,over):
    #对next_state评估需要先把它对应的当作计算出来
    action = model_action_next(next_state)
    
    #和value的计算一样,action拼合进next_state里综合计算
    input = torch.act([next_state,action],dim=1)
    target = model_value_next(input)*0.98
    target *=(1-over)
    target +=reward
    return target

action模型的loss

def get_loss_action(state):
    #首先把动作计算出来
    action  = model_action(state)
    
    #像value计算那里一样,拼合state和action综合计算
    input = torch.cat([state,action],dim = 1)
    
    #使用value网络评估动作的价值,价值越高越好
    #因为这里是在计算loss,loss是越小越好,所以符号取反
    loss =-model_value(input).mean()
    
    return loss

软更新函数,DQN使用硬更新

软更新(Soft Update)是深度强化学习中用于更新目标网络参数的一种技术。在某些强化学习算法,如深度确定性策略梯度(DDPG)算法中,会使用两个相似的网络:一个用于生成当前策略或价值函数的“主网络”(online network),以及一个“目标网络”(target network)。

目标网络的参数是主网络参数的慢速更新版本,这样做的目的是增加训练过程的稳定性。软更新的具体步骤如下:

1. **初始化**:开始时,目标网络的参数被复制或初始化为主网络参数的副本。

2. **慢速更新**:在每次训练迭代中,以一个小的比例(通常是一个小于1的因子,如0.001或0.005)更新目标网络的参数。这个更新过程可以表示为:
 
   其中, 是目标网络的参数, 是主网络的参数,而是更新比例(tau 系数)。

3. **逐步逼近**:通过这种方式,目标网络的参数会逐步逼近主网络的参数,但不会立即完全同步。这有助于减少训练过程中的震荡。

软更新的优点包括:

- **稳定性**:由于目标网络参数更新得更慢,它为训练过程提供了一定程度的稳定性。
- **减少震荡**:软更新减少了目标值的突然变化,这有助于避免训练中的大振荡。
- **平滑学习**:它允许模型在更新过程中保持平滑的学习曲线。

软更新通常在算法的每次迭代或每隔几个步骤执行一次,具体取决于算法的设计和所需的更新频率。
 

def train():
    model_action.train()  #设置模型为训练模式
    model_value.train()
    optimizer_action = torch.optim.Adan(model.parameters(),lr =5e-4) #创建优化器
    optimizer_value = torch.optim.Adam(model_td.parameters(),lr=5e-3)
    loss_fn = torch.nn.MSELoss()
    
    #玩N局游戏,每局训练一次
    for epoch in range(200):
        #更新N条数据
        update_data()
        
        for i in range(200):
            #玩一局游戏,得到数据
            states,rewards,actions,next_states,overs = get_sample()

            #计算values 和targets
            values= get_value(state,action)
            targets = get_target(next_states,reward,over)


            #两者求差,计算loss,更新参数
            loss_value= loss_fn(values,targets)

            #更新参数
            optimizer.zero_grad()   #作用是清除(重置)模型参数的梯度
            loss.backward()       #反向传播计算梯度的标准方法
            optimizer.step()     #更新模型的参数

            #使用value网络评估action网络的loss,更新参数
            loss_action = get_loss_action(state)

            optimizer_td.zero_grad()  
            loss_td.backward()       
            optimizer_td.step()  

            #以一个小的比例更新
            soft_update(model_action,model_action_next)
            soft_update(model_value,model_value_next)

        if i %20 ==0:
            test_result = sum([test(play=False)for _ in range(10)])/10
            print(epoch,len(datas),test_result)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值