强化学习入门必读 | 跨过DQN !

本文首发于:行者AI

DRL(Deep Reinforcement Learning)的首次惊艳亮相,应该是 DeepMind 在2013年首次将其应用于 Atari 游戏中提出的 DQN(Deep Q Network)算法。时至今日,DRL 已经从玩 Atari,进化为下围棋(Alphago)、玩电竞(Dota AI、StarCraft AI),一次次刷新大家的三观。

1. 什么是Q-Learning

Q-Learning算法是一种使用时序差分求解强化学习控制问题的方法。通过当前的状态S,动作A,即时奖励R,衰减因子γ,探索率ϵ,就最最优的动作价值函数Q和最有策略π

  • S:表示环境的状态,在t时刻环境的状态S_t

  • A:agent的动作,在t时刻采取的动作A_t

  • R:环境的奖励,在t时刻agent在状态St采取动作A_t对应的奖励R_{t+1} 会在 t+1 时刻得到

  • \gamma:折扣因子, 当前延时奖励的权重

  • \epsilon:探索率,在Q-learning我们会选取当前轮迭代价值最大的动作,可能会导致有的动作重来都没被执行过,在agent选择动作时,有小概率不是选取当前迭代价值最大的动作。

1.1 Q-Learning算法简介

首先我们基于状态S,用ϵ−greed(贪心)选择到动作A, 然后执行动作A,得到奖励R,并进入状态S'Q值的更新公式如下:​

Q(S,A)=Q(S,A)+\alpha(R+\gamma maxQ(S',a)-Q(S,A))

1.2 Q-learning的算法流程

  • 随机初始化状态和动作价值对应的价值。(初始化Q表格)

  • for i from 1 to TT:迭代的总轮数)
            a)初始化S为当前状态的序列的第一个状态
            b)用ϵ−贪婪法在当前状态S选择出动作A
            c)在状态S执行当前动作A,得到新状态S′和奖励R
            d)更新价值函数Q(S,A)
                                  Q(S,A)=Q(S,A)+\alpha(R+\gamma maxQ(S',a)-Q(S,A))

            e)S=S'
            f) if done 完成当前迭代

1.3 关于Q_table举个例子

(1)游戏地图

  • 黑色的框为陷阱

  • 黄色的框为出口(奖励点)

(2) 这是一个训练模型之后的Q表格

(3) 举个简单的例子

  • 如果agent在“1”的位置进入迷宫,会更具Q表格,向下走的Q值最大为0.59,那么agent就会走到“5”的位置。
  • agent在“5”的位置之后,更具Q表格,向下走的Q值最大为0.66,依然是向下走,那么agent就走到了“9”的位置。
  • agent在“9”的位置之后,更具Q表格,向右走的Q值最大为0.73,依然是向下走,那么agent就走到了“10”的位置。
  • agent在“10”的位置之后,更具Q表格,向下走的Q值最大为0.81,依然是向下走,那么agent就走到了“14”的位置。
  • agent在“14”的位置之后,更具Q表格,向右走的Q值最大为0.9,依然是向下走,那么agent就走到了“15”的位置。
  • agent在“15”的位置之后,更具Q表格,向右走的Q值最大为1,依然是向下走,那么agent就走到了“16”的位置,到达终点。

最后agent的动作路线为1-->5-->9-->10-->14-->15-->16

每跑一次,Q表格的值都会有所改变,但是原理不变。

如果想看到更加直观的视觉戳这里

2. DQN(Deep Q Network)

前面讲过Q-Learning的决策是根据Q表格的值,执行那个动作后得到的奖励更多,就选取那个动作执行。前面所讲的状态空间和动作空间都很小,如果状态空间和动作空间变得很大很大,那我们还能用一个Q表格来表示吗?显然不可以,就引入了价值函数近似

2.1 价值函数近似

由于在实际问题中,一个问题的状态规模很大,一个可行的解决办法就是使用价值函数近似。我们引入一个状态价值函数\hat v,由权重\omega描述,以状态s作为输入,计算得到状态s的价值:
\hat v(s,w)\approx v_\pi(s)

上面我们提到的\omega就相当于我们神经网络中的参数,通过输入的状态s,采用MC(蒙特卡洛)/TD(时序差分)计算出价值函数作为输出,然后对权重\omega进行训练,直到收敛。事实上,所谓的DQN就是将神经网络和Q-Learning结合,将Q表格变成了Q网络。

2.2 Deep Q-Learning算法思路

DQN是一种Off-Policy算法,用李宏毅老师的话讲,可以看着别人学习,那么DQN为什么能够看着别人学习呢?DQN采用了一种经验回放的方式进行学习。每次agent和环境交互得到的奖励,当前状态和下一个状态等数据保存起来,用于后面Q网络的更新。

下面我们看下Nature DQN,其实Nature DQN为DQN第二代了,DQN NIPS为最原始的DQN,在这之上的还有很多的DQN的版本,比如Double DQN、Dueling DQN等等。之所以在这儿给大家介绍Nature DQN呢!个人觉得这个版本的DQN,应该是最经典的了。接下来我们看看DQN是如何进行强化学习的吧。

2.3 算法流程图

输入:总迭代轮数T,状态特征维度n,动作维度A, 步长a,衰减因子\gamma, 探索率\epsilon, 当前Q网络Q,目标Q网络Q', 批量梯度下降的样本数m,目标Q网络参数更新频率P

输出:Q网络参数

  • 随机初始化所有的状态和动作对应的价值Q,随机初始化当前Q网络的所有参数\omega,初始化目标Q网络Q'的参数\omega'=\omega,清空经验池D
  • for i from 1 to T(不断地迭代)
              a)初始化环境,获取第一个状态s,获取特征向量\phi(S)
              b)在Q网络中使用\phi(S)作为输入,得到Q网络所有动作的Q值,使用\epsilon-贪婪法在当前的Q值输出中选择对应的动作A
              c)在状态S下执行动作A,得到新的状态S',以及其对应的\phi(S')和奖励R,是否为结束状态isdone
              d)将{\phi(S),   A,   R,  \phi(S'),   isdone }将这5个元素放入经验池D
              e) S=S'
              f)从经验池D中采取m个样本,{\phi(S_j),   A_j,   R_j,  \phi(S'_jisdone_j),j=1,2,3,4....m,计算当前Qy_j:

          g)使用均方差损失函数\left(\frac{1}{m}\right)\sum_{j=1}^m(y_j-Q(\phi (S_j),A_j,\omega))^2通过神经网络梯度下降反向传播更新参数\omega
          h)如果i%P=0,跟新目标Q网络的参数\omega'=\omega
          i)如果S'为终止状态,则当前迭代完毕,否则跳转到步骤(2)

2.4 DQN实现代码

(1) 网络结构

class Net(nn.Module):
    def __init__(self, ):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(N_STATES, 50)
        self.fc1.weight.data.normal_(0, 0.1)   # initialization
        self.out = nn.Linear(50, N_ACTIONS)
        self.out.weight.data.normal_(0, 0.1)   # initialization
    def forward(self, x):
        x = self.fc1(x)
        x = F.relu(x)
        actions_value = self.out(x)
        return actions_value
  • 两个网络的结构一样
  • 参数权重有区别,一个是实时更新,一个是隔一段时间在更新。

(2) 动作的选取

    def choose_action(self, x):  #x为当前状态的4个值
        x = torch.unsqueeze(torch.FloatTensor(x), 0)  #在数据的第0维处增加一维
        # input only one sample
        if np.random.uniform() < EPSILON:   # greedy #贪婪取法
            actions_value = self.eval_net.forward(x)  ##传入eval_net获取下一个的动作
            action = torch.max(actions_value, 1)[1].data.numpy()  ##返回这一行中最大值的索引
            action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)  # return the argmax index
        else:   # random
            action = np.random.randint(0, N_ACTIONS)
            # action = random.sample(N_ACTIONS)
            action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
        return action

加入了一个探索值(\epsilon),在即小的可能性是随机选择动作。

(3) 经验池

    def store_transition(self, s, a, r, s_):  #s和s_都为4个值,分别为  位置 移动速度  角度  移动角度
        transition = np.hstack((s, [a, r], s_))
        # replace the old memory with new memory #更新经验
        index = self.memory_counter % MEMORY_CAPACITY
        self.memory[index, :] = transition  #将第index经验替换为transition
        self.memory_counter += 1

(4) 更新网络参数

 def learn(self):
        # target parameter update 目标参数更新
        if self.learn_step_counter % TARGET_REPLACE_ITER == 0:
            self.target_net.load_state_dict(self.eval_net.state_dict())  ## 每学习200步将eval_net的参数赋值给target_net
        self.learn_step_counter += 1
        # sample batch transitions  #选取过渡
        sample_index = np.random.choice(MEMORY_CAPACITY, BATCH_SIZE) #从MEMORY_CAPACITY随机选取BATCH_SIZE个
        b_memory = self.memory[sample_index, :]
        b_s = torch.FloatTensor(b_memory[:, :N_STATES])  #第一个状态
        b_a = torch.LongTensor(b_memory[:, N_STATES:N_STATES+1].astype(int)) #动作
        print("--------")
        print(b_a)
        print("-----")
        b_r = torch.FloatTensor(b_memory[:, N_STATES+1:N_STATES+2]) #得分
        b_s_ = torch.FloatTensor(b_memory[:, -N_STATES:]) #下一个状态
        # q_eval w.r.t the action in experience
        q_eval = self.eval_net(b_s).gather(1, b_a)   # shape (batch, 1) 当前状态的Q值使用eval_net计算
        # print("++++++")
        # print(self.eval_net(b_s))
        # print(self.eval_net(b_s).gather(1,b_a))
        # print("+++++++")

        q_next = self.target_net(b_s_).detach()   #使用target_net计算下一步Q值  # detach from graph, don't backpropagate detach防止targent——net反向传播
        q_target = b_r + GAMMA * q_next.max(1)[0].view(BATCH_SIZE, 1)   # shape (batch, 1)
        loss = self.loss_func(q_eval, q_target)
        self.optimizer.zero_grad()   #zer——grad设置所有优化器的梯度为0
        loss.backward()   #反向传播
        self.optimizer.step()    #执行下个优化

DQN是深度强化学习的门槛,只要踏进了大门,后面的学习就会很轻松。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容