深度学习介绍与DQN


一、Reinforcement Learning简介

什么是强化学习?
强化学习是机器学习的一大分支。强化学习是让计算机实现不断尝试来从错误中学习从而找到规律达成目标的一种算法的统称。比如 阿尔法狗等。就是让计算机不断地从新环境中学习来更新自己的准则,不断进步的过程。(有点类似监督学习的神经网络,但是强化学习是没有label标签的)具有分数导向性。

RL 常用算法

价值导向直接选择想象环境学习
Q learningPolicy Gradientsmodel based RL
Sarsa
Deep Q network

二、强化学习方法分类

1.理解环境(model based)/不理解环境(model free)

model based 相较于 model free 需要为虚拟世界建模,拥有“想象力”,而常见的model free 算法有 Q learning ,sarsa 和 policy gradient。

2.基于概率(policy-based)/基于价值(value-based)

基于概率的模型适合连续性,且具有选择性(依靠概率分布选择),即概率最大的key不一定被选到(policy gradients)
但是基于价值则具有唯一性,拥有都选择value 最大的key。(Q learning ,sarsa)

3.回合更新(Monte Carlo update)/单步更新(temporal- difference update)

每一轮进行更新(类似于批处理)
policy gradients
monte-carlo learning
每一步都要更新(边游戏边学习)(现在更常用)
Q learning
sarsa

4. 在线学习(on-policy)/ 离线学习(off - policy)

在线学习
sarsa
sarsa(λ)
离线学习
Q Learning
deep q network


三 、知识准备

在机器学习领域,更多的人倾向于基于Python来完成算法,我们需要的知识贮备有:
numpy,pandas:数据处理分析
matplotlib:绘图误差
tkinter/openai gym:编写模拟环境
pytorch:神经网络

四 、深度强化学习DQN的说明

Q学习中,对于常见的倒立摆任务中,智能体的状态是对四个变量分别进行离散化转化为数值,动作价值是在时刻t,状态 s t s_t st下采取动作是将获得的折扣奖励总和。但是Q表的问题就是当状态变量的类型数量增加,每个变量都要被精准的离散化,会导致表格的行数十分巨大,钦此,用表格表示的强化学习很难解决大量状态的任务。于是我们提出了深度神经网络表示动作价值函数。
神经网络的输入是每个状态变量的值。因此神经网络输入层中的神经元数量也状态变量的数量相同,这样就不需要考虑对连续的状态变量进行离散化,输出层的神经元数量就是动作类型的数量。输出层中神经元输出的值是动作价值函数 Q ( s t , a t ) Q\left( s_t,a_t \right) Q(st,at)的值。因此他会输出采用这个动作之后所得到的的折扣奖励总和。然后比较来确定选择的行动。
对于Q-learning而言:
Q ( s t , a t ) = Q ( s t , a t ) + η ∗ ( R t + 1 + γ max ⁡ a Q ( s t + 1 + a ) − Q ( s t , a t ) ) Q\left(s_{t}, a_{t}\right)=Q\left(s_{t}, a_{t}\right)+\eta^{*}\left(R_{t+1}+\gamma \max _{a} Q\left(s_{t+1}+a\right)-Q\left(s_{t}, a_{t}\right)\right) Q(st,at)=Q(st,at)+η(Rt+1+γamaxQ(st+1+a)Q(st,at))

使用这个更新公式的原因是我们想要构造一个这样的表达式:
Q ( s t , a t ) = R t + 1 + γ max ⁡ a Q ( s t + 1 , a ) Q\left(s_{t}, a_{t}\right)=R_{t+1}+\gamma \max _{a} Q\left(s_{t+1}, a\right) Q(st,at)=Rt+1+γamaxQ(st+1,a)
因为一个神经网络中我们需要计算实际输出与想要的值之间的差值,将其平方值作为误差来进行训练。在这个问题中,在时间t的状态 s t s_t st下采用动作 a t a_t at,则输出层的神经元输出的值是 Q ( s t , a t ) Q\left(s_{t}, a_{t}\right) Q(st,at), 经过学习和训练,我们使得输出值和 R t + 1 + γ max ⁡ a Q ( s t + 1 , a ) R_{t+1}+\gamma \max _{a} Q\left(s_{t+1}, a\right) Rt+1+γmaxaQ(st+1,a)接近。 因为 这两个值本来应该是相当的,t时刻的奖励与t+1时刻的奖励只差 R t + 1 R_{t+1} Rt+1.所以误差函数是:
E ( s t , a t ) = ( R t + 1 + γ max ⁡ a Q ( s t + 1 , a ) − Q ( s t , a t ) ) 2 E\left(s_{t}, a_{t}\right)=\left(R_{t+1}+\gamma \max _{a} Q\left(s_{t+1}, a\right)-Q\left(s_{t}, a_{t}\right)\right)^{2} E(st,at)=(Rt+1+γamaxQ(st+1,a)Q(st,at))2
但是,由于状态 s t + 1 s_{t+1} st+1实际上是由 s t s_t st状态下采取动作 a t a_t at后取得的,所以要通过将状态 s t + 1 s_{t+1} st+1输入神经网络来获得 max ⁡ a Q ( s t + 1 , a ) \max _{a} Q\left(s_{t+1}, a\right) maxaQ(st+1,a)的值。
这就是深度学习来表示强化学习的动作价值函数的基本方法,也就是DQN(deep-q-network).


五、实现DQN的4个要点

经验回放(experience replay)

DQN不像Q-learning一样,并不是每一步都学习该步的内容,而是将内容储存在经验池中并随机从中提取(replay)内容进行学习,每个步骤的内容也成为transition。我们这样做的原因是因为如果每一步都学习那么t时刻和t+1时刻的时间相关性太高,参数学习难以稳定,所以采用经验回放使用小批量进行训练神经网络。

固定目标Q网络(fixed target Q-network)

有两种类型的神经网络:确定动作的主网络和计算误差函数时确定动作价值的目标网络。因为我们在更新价值函数时需要下一个时刻的状态的价值函数,也就是要用相同的价值函数来更新,然而相同的函数会出现Q函数更新学习不稳定的情况,所以我们在求 max ⁡ a Q ( s t + 1 , a ) \max _{a} Q\left(s_{t+1}, a\right) maxaQ(st+1,a)的值时,使用一段时间之前的另一个Q函数(固定目标Q网络)来计算。

奖励的裁剪( reward clipping)

为了简便,我们可以在每个步骤中的奖励固定为-1,0,1.这样无论学习任务如何,都可以使用相同的超参数

Huber函数

我们不采用平方误差函数,因为当误差很大时,平方误差会导致误差函数的输出过大。
Huber损失对数据中的异常点没有平方误差损失那么敏感。
本质上,Huber损失是绝对误差,只是在误差很小时,就变为平方误差。误差降到多小时变为二次误差由超参数δ(delta)来控制。当Huber损失在[0-δ,0+δ]之间时,等价为MSE,而在[-∞,δ]和[δ,+∞]时为MAE。
L δ ( y , f ( x ) ) = { 1 2 ( y − f ( x ) ) 2  for  ∣ y − f ( x ) ∣ ≤ δ δ ∣ y − f ( x ) ∣ − 1 2 δ 2  otherwise  L_{\delta}(y, f(x))=\left\{\begin{array}{ll} \frac{1}{2}(y-f(x))^{2} & \text { for }|y-f(x)| \leq \delta \\ \delta|y-f(x)|-\frac{1}{2} \delta^{2} & \text { otherwise } \end{array}\right. Lδ(y,f(x))={21(yf(x))2δyf(x)21δ2 for yf(x)δ otherwise 
Huber损失结合了MSE和MAE的优点,对异常点更加鲁棒。

六、使用pytorch实现DQN的代码(cartpole问题)

代码如下(示例)建议使用jupyter notebook:

# cartpole文件在   环境文件夹\Lib\site-packages\gym\envs\classic_control
# gym安装:pip install gym matplotlib -i  https://pypi.tuna.tsinghua.edu.cn/simple
import random
import torch
import torch.nn as nn
import numpy as np
import gym

class Network(nn.Module):
    def __init__(self):
        super(Network, self).__init__()
        self.fc = nn.Sequential(
            nn.Linear(4, 24),
            nn.ReLU(),
            nn.Linear(24, 24),
            nn.ReLU(),
            nn.Linear(24, 2)
        )
        self.mls = nn.MSELoss()
        self.opt = torch.optim.Adam(self.parameters(), lr = 0.001)

    def forward(self, inputs):
        return self.fc(inputs)


env = gym.envs.make('CartPole-v1')
env = env.unwrapped
net = Network()  # 学习的网络
net2 = Network()  # 延迟的网络

memory_count = 0  # 经验池中已经遇到的情况
memory_size = 2000  # 记忆库大小
epsilon = 0.5  # 贪婪系数
gama = 0.9  # 时间折扣
b_size = 500  # batch size每次从记忆库中提取的数据
learn_time = 0
update_time = 10  # 每10步更新一次网络
memory = np.zeros((memory_size, 10))  # s=4,a=1,s=4,r=1,
start_study = False
for i in range(50000):
    s = env.reset()
    while True:
        if random.randint(0,100) < 100*(epsilon**learn_time):
            a = random.randint(0,1)
        else:
            totalreward = net(torch.Tensor(s))
            a = torch.argmax(totalreward).data.item()
        s_, r, done, info = env.step(a)
        r = ( env.theta_threshold_radians - abs(s_[2]) ) / env.theta_threshold_radians * 0.7  +  ( env.x_threshold - abs(s_[0]) ) / env.x_threshold * 0.3  # (杆子角度为0最好,在中间也很好,比例定为7/3)
        memory[memory_count % memory_size][0:4] = s
        memory[memory_count % memory_size][4:5] = a
        memory[memory_count % memory_size][5:9] = s_
        memory[memory_count % memory_size][9:10] = r
        memory_count += 1
        s = s_

        if memory_count > memory_size:

            if learn_time % update_time == 0:
                net2.load_state_dict(net.state_dict())  # 延迟更新

            index = random.randint(0, memory_size - b_size -1)
            b_s  = torch.Tensor(store[index:index + b_size, 0:4])
            b_a  = torch.Tensor(store[index:index + b_size, 4:5]).long()
            b_s_ = torch.Tensor(store[index:index + b_size, 5:9])
            b_r  = torch.Tensor(store[index:index + b_size, 9:10])

            q = net(b_s).gather(1, b_a)
            q_next = net2(b_s_).detach().max(1)[0].reshape(b_size, 1)
            tq = b_r + gama * q_next
            loss = net.mls(q, tq) # 让总收益等于下一步收益加之后的收益
            net.opt.zero_grad()
            loss.backward()
            net.opt.step()

            learn_time += 1
            if not start_study:
                print('start study')
                start_study = True
                break
        if done:
            break

        env.render()

参考文献 【1】边做边学深度强化学习,YUTARO OGAWA著 【2】莫烦python强化学习 【3】Python·Pytorch-一点一点学AI-5-人人都可以学会的强化学习DQN(Deep Q-Learning)https://www.bilibili.com/video/BV1Ab411w7Yd?t=3359
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值