精华内容
下载资源
问答
  • 【强化学习】Q-Learning算法详解

    万次阅读 多人点赞 2018-06-19 21:18:18
    QLearning是强化学习算法中值迭代的算法,Q即为Q(s,a)就是在某一时刻的 s 状态下(s∈S),采取 a (a∈A)动作能够获得收益的期望,环境会根据agent的动作反馈相应的回报reward r,所以算法的主要思想就是将State与...

    【强化学习】Q-Learning详解

    https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/2-1-general-rl/ 莫凡大神的有趣的强化学习视频通俗易懂

    发现了很多RL资料搬砖过来,刚入门的可以用得上

    David Silver 博士的 UCL 公开课:http://www0.cs.ucl.ac.uk/staff/d.silver/web/Teaching.html
    DeepMind 和 UCL 的DL、RL课程:https://www.youtube.com/playlist?list=PLqYmG7hTraZDNJre23vqCGIVpfZ_K2RZs
    Sergey Levine 的DRL课程:http://rail.eecs.berkeley.edu/deeprlcourse/
    OpenAI 的 Spinning Up in Deep RL:https://blog.openai.com/spinning-up-in-deep-rl/
    关于深度强化学习良心paper:https://arxiv.org/abs/1810.06339

    1、算法思想

    QLearning是强化学习算法中value-based的算法,Q即为Q(s,a)就是在某一时刻的 s 状态下(s∈S),采取 动作a (a∈A)动作能够获得收益的期望,环境会根据agent的动作反馈相应的回报reward r,所以算法的主要思想就是将State与Action构建成一张Q-table来存储Q值,然后根据Q值来选取能够获得最大的收益的动作。

    Q-Tablea1a2
    s1q(s1,a1)q(s1,a2)
    s2q(s2,a1)q(s2,a2)
    s3q(s3,a1)q(s3,a2)

    2、公式推导

    举个例子如图有一个GridWorld的游戏从起点出发到达终点为胜利掉进陷阱为失败。智能体(Agent)、环境状态(environment)、奖励(reward)、动作(action)可以将问题抽象成一个马尔科夫决策过程,我们在每个格子都算是一个状态 s t s_t st , π(a|s)在s状态下采取动作a策略 。 P(s’|s,a)也可以写成 P s s ′ a P_{ss'}^a Pssa为在s状态下选择a动作转换到下一个状态s’的概率。R(s’|s,a)表示在s状态下采取a动作转移到s’的奖励reward,我们的目的很明确就是找到一条能够到达终点获得最大奖赏的策略。
    这里写图片描述
    所以目标就是求出累计奖励最大的策略的期望:

    Goal: max ⁡ π E [ ∑ t = 0 H γ t R ( S t , A t , S t + 1 ) ∣ π ] \max_πE[\sum_{t=0}^{H}γ^tR(S_t,A_t,S_{t+1}) | π] maxπE[t=0HγtR(St,At,St+1)π]

    Qlearning的主要优势就是使用了时间差分法TD(融合了蒙特卡洛和动态规划)能够进行离线学习, 使用bellman方程可以对马尔科夫过程求解最优策略

    贝尔曼方程

    通过bellman方程求解马尔科夫决策过程的最佳决策序列,状态值函数 V π ( s ) V_\pi(s) Vπ(s)可以评价当前状态的好坏,每个状态的值不仅由当前状态决定还要由后面的状态决定,所以状态的累计奖励求期望就可得出当前s的状态值函数V(s)。bellman方程如下

    V π ( s ) = E ( U t ∣ S t = s ) V_π(s) = E(U_t|S_t = s) Vπ(s)=E(UtSt=s)
    V π ( s ) = E π [ R t + 1 + γ [ R t + 2 + γ [ . . . . . . . ] ] ∣ S t = s ] V_π(s) = E_π[R_{t+1}+γ[R_{t+2} + γ[.......]]|S_t = s] Vπ(s)=Eπ[Rt+1+γ[Rt+2+γ[.......]]St=s]
    V π ( s ) = E π [ R t + 1 + γ V ( s ′ ) ∣ S t = s ] V_π(s) = E_π[R_{t+1}+γV(s')|S_t = s] Vπ(s)=Eπ[Rt+1+γV(s)St=s]

    最优累计期望可用 V ∗ ( s ) V^*(s) V(s)表示,可知最优值函数就是 V ∗ ( s ) = m a x π V π ( s ) V^*(s)=max_πV_\pi(s) V(s)=maxπVπ(s)
    V ∗ ( s ) = max ⁡ π E [ ∑ t = 0 H γ t R ( S t , A t , S t + 1 ) ∣ π , s 0 = s ] V^*(s)=\max_πE[\sum_{t=0}^{H}γ^tR(S_t,A_t,S_{t+1}) | π,s_0=s] V(s)=maxπE[t=0HγtR(St,At,St+1)π,s0=s]

    Q(s,a)状态动作值函数
    q π ( s , a ) = E π [ r t + 1 + γ r t + 2 + γ 2 r t + 3 + . . . . ∣ A t = a , S t = s ] q_π(s,a) = E_π[r_{t+1}+γr_{t+2}+γ^2r_{t+3}+....|A_t=a,S_t=s] qπ(s,a)=Eπ[rt+1+γrt+2+γ2rt+3+....At=a,St=s]
    q π ( s , a ) = E π [ G t ∣ A t = a , S t = s ] q_π(s,a) = E_π[G_t|A_t=a,S_t=s] qπ(s,a)=Eπ[GtAt=a,St=s]
    其中 G t G_t Gt是t时刻开始的总折扣奖励,从这里我们能看出来 γ衰变值对Q函数的影响,γ越接近于1代表它越有远见会着重考虑后续状态的的价值,当γ接近0的时候就会变得近视只考虑当前的利益的影响。所以从0到1,算法就会越来越会考虑后续回报的影响。
    q π ( s , a ) = E π [ R t + 1 + γ q π ( S t + 1 , A t + 1 ) ∣ A t = a , S t = s ] q_π(s,a) = E_π[R_{t+1}+γq_π(S_{t+1},A_{t+1})|A_t=a,S_t=s] qπ(s,a)=Eπ[Rt+1+γqπ(St+1,At+1)At=a,St=s]

    最优价值动作函数 Q ∗ ( s , a ) = m a x π Q ∗ ( s , a ) Q^*(s,a)=max_\pi Q^*(s,a) Q(s,a)=maxπQ(s,a),打开期望如下
    Q ∗ ( s , a ) = ∑ s ′ P ( s ′ ∣ s , a ) ( R ( s , a , s ′ ) + γ max ⁡ a ′ Q ∗ ( s ′ , a ′ ) ) Q^*(s,a)=\sum_{s'} P(s'|s,a)(R(s,a,s')+γ\max_{a'}Q^*(s',a')) Q(s,a)=sP(ss,a)(R(s,a,s)+γmaxaQ(s,a))

    Bellman方程实际上就是价值动作函数的转换关系

    V π ( s ) = ∑ a ∈ A π ( a ∣ s ) q π ( s , a ) V_π(s) = \sum_{a∈A}π(a|s)q_π(s,a) Vπ(s)=aAπ(as)qπ(s,a)
    q π ( s , a ) = R s a + γ ∑ s ′ ∈ S P s s ′ a V π ( s ′ ) q_π(s,a) = R_s^a + γ\sum_{s'∈S}P_{ss'}^aV_π(s') qπ(s,a)=Rsa+γsSPssaVπ(s)
    V π ( s ) = ∑ a ′ ∈ A π ( a ∣ s ) [ R s a + γ ∑ s ′ P s s ′ a V π ( s ′ ) ] V_π(s)=\sum_{a'∈A}π(a|s)[R_s^a+γ\sum_{s'}P_{ss'}^aV_π(s')] Vπ(s)=aAπ(as)[Rsa+γsPssaVπ(s)]

    Q值迭代公式
    根据下图更直观的了解V(s)与Q(s,a)的关系
    V(s)与Q(s,a)的关系

    时间差分法 https://blog.csdn.net/qq_30615903/article/details/80821061

    时间差分方法结合了蒙特卡罗的采样方法和动态规划方法的bootstrapping(利用后继状态的值函数估计当前值函数)使得他可以适用于model-free的算法并且是单步更新,速度更快。值函数计算方式如下

    V ( s ) ← V ( s ) + α ( R t + 1 + γ V ( s ′ ) − V ( s ) ) V(s)←V(s)+\alpha (R_{t+1}+\gamma V(s')-V(s)) V(s)V(s)+α(Rt+1+γV(s)V(s))

    其中 R t + 1 + γ V ( s ′ ) R_{t+1}+\gamma V(s') Rt+1+γV(s)被称为TD目标, δ t = R t + 1 + γ V ( s ′ ) − V ( s ) \delta_t=R_{t+1}+\gamma V(s')-V(s) δt=Rt+1+γV(s)V(s) 称为TD偏差。

    3、更新公式

    根据以上推导可以对Q值进行计算,所以有了Q值我们就可以进行学习,也就是Q-table的更新过程,其中α为学习率γ为奖励性衰变系数,采用时间差分法的方法进行更新。

    Q ( s , a ) ← Q ( s , a ) + α [ r + γ m a x a ′ Q ( s ′ , a ′ ) − Q ( s , a ) ] Q(s,a) ← Q(s,a) + α[r + γmax_{a'}Q(s',a')-Q(s,a)] Q(s,a)Q(s,a)+α[r+γmaxaQ(s,a)Q(s,a)]

    上式就是Q-learning更新的公式,根据下一个状态s’中选取最大的 Q ( s ′ , a ′ ) Q(s',a') Q(s,a)值乘以衰变γ加上真实回报值最为Q现实,而根据过往Q表里面的Q(s,a)作为Q估计。
    在这里插入图片描述
    这里写图片描述

    4、实现代码

    代码来自网上各路大神的源码,非原创,据反映没图片跑不通,所以建了个github,https://github.com/xshura/reinforcement_learning
    Q-Learning agent

    # -*- coding: utf-8 -*-
    import random
    from environment import Env
    from collections import defaultdict
    
    
    class QLearningAgent:
        def __init__(self, actions):
            # actions = [0, 1, 2, 3]
            self.actions = actions
            self.learning_rate = 0.01
            self.discount_factor = 0.9
            self.epsilon = 0.1
            self.q_table = defaultdict(lambda: [0.0, 0.0, 0.0, 0.0])
    
        # 采样 <s, a, r, s'>
        def learn(self, state, action, reward, next_state):
            current_q = self.q_table[state][action]
            # 贝尔曼方程更新
            new_q = reward + self.discount_factor * max(self.q_table[next_state])
            self.q_table[state][action] += self.learning_rate * (new_q - current_q)
    
        # 从Q-table中选取动作
        def get_action(self, state):
            if np.random.rand() < self.epsilon:
                # 贪婪策略随机探索动作
                action = np.random.choice(self.actions)
            else:
                # 从q表中选择
                state_action = self.q_table[state]
                action = self.arg_max(state_action)
            return action
    
        @staticmethod
        def arg_max(state_action):
            max_index_list = []
            max_value = state_action[0]
            for index, value in enumerate(state_action):
                if value > max_value:
                    max_index_list.clear()
                    max_value = value
                    max_index_list.append(index)
                elif value == max_value:
                    max_index_list.append(index)
            return random.choice(max_index_list)
    
    
    if __name__ == "__main__":
        env = Env()
        agent = QLearningAgent(actions=list(range(env.n_actions)))
        for episode in range(1000):
            state = env.reset()
            while True:
                env.render()
                # agent产生动作
                action = agent.get_action(str(state))
                next_state, reward, done = env.step(action)
                # 更新Q表
                agent.learn(str(state), action, reward, str(next_state))
                state = next_state
                env.print_value_all(agent.q_table)
                # 当到达终点就终止游戏开始新一轮训练
                if done:
                    break
    

    环境部分

    import time
    import numpy as np
    import tkinter as tk
    from PIL import ImageTk, Image
    
    np.random.seed(1)
    PhotoImage = ImageTk.PhotoImage
    UNIT = 100
    HEIGHT = 5
    WIDTH = 5
    
    
    class Env(tk.Tk):
        def __init__(self):
            super(Env, self).__init__()
            self.action_space = ['u', 'd', 'l', 'r']
            self.n_actions = len(self.action_space)
            self.title('Q Learning')
            self.geometry('{0}x{1}'.format(HEIGHT * UNIT, HEIGHT * UNIT))
            self.shapes = self.load_images()
            self.canvas = self._build_canvas()
            self.texts = []
    
        def _build_canvas(self):
            canvas = tk.Canvas(self, bg='white',
                               height=HEIGHT * UNIT,
                               width=WIDTH * UNIT)
            # create grids
            for c in range(0, WIDTH * UNIT, UNIT):  # 0~400 by 80
                x0, y0, x1, y1 = c, 0, c, HEIGHT * UNIT
                canvas.create_line(x0, y0, x1, y1)
            for r in range(0, HEIGHT * UNIT, UNIT):  # 0~400 by 80
                x0, y0, x1, y1 = 0, r, HEIGHT * UNIT, r
                canvas.create_line(x0, y0, x1, y1)
    
            # add img to canvas
            self.rectangle = canvas.create_image(50, 50, image=self.shapes[0])
            self.triangle1 = canvas.create_image(250, 150, image=self.shapes[1])
            self.triangle2 = canvas.create_image(150, 250, image=self.shapes[1])
            self.circle = canvas.create_image(250, 250, image=self.shapes[2])
    
            # pack all
            canvas.pack()
    
            return canvas
    
        def load_images(self):
            rectangle = PhotoImage(
                Image.open("../img/rectangle.png").resize((65, 65)))
            triangle = PhotoImage(
                Image.open("../img/triangle.png").resize((65, 65)))
            circle = PhotoImage(
                Image.open("../img/circle.png").resize((65, 65)))
    
            return rectangle, triangle, circle
    
        def text_value(self, row, col, contents, action, font='Helvetica', size=10,
                       style='normal', anchor="nw"):
            if action == 0:
                origin_x, origin_y = 7, 42
            elif action == 1:
                origin_x, origin_y = 85, 42
            elif action == 2:
                origin_x, origin_y = 42, 5
            else:
                origin_x, origin_y = 42, 77
    
            x, y = origin_y + (UNIT * col), origin_x + (UNIT * row)
            font = (font, str(size), style)
            text = self.canvas.create_text(x, y, fill="black", text=contents,
                                           font=font, anchor=anchor)
            return self.texts.append(text)
    
        def print_value_all(self, q_table):
            for i in self.texts:
                self.canvas.delete(i)
            self.texts.clear()
            for i in range(HEIGHT):
                for j in range(WIDTH):
                    for action in range(0, 4):
                        state = [i, j]
                        if str(state) in q_table.keys():
                            temp = q_table[str(state)][action]
                            self.text_value(j, i, round(temp, 2), action)
    
        def coords_to_state(self, coords):
            x = int((coords[0] - 50) / 100)
            y = int((coords[1] - 50) / 100)
            return [x, y]
    
        def state_to_coords(self, state):
            x = int(state[0] * 100 + 50)
            y = int(state[1] * 100 + 50)
            return [x, y]
    
        def reset(self):
            self.update()
            time.sleep(0.5)
            x, y = self.canvas.coords(self.rectangle)
            self.canvas.move(self.rectangle, UNIT / 2 - x, UNIT / 2 - y)
            self.render()
            # return observation
            return self.coords_to_state(self.canvas.coords(self.rectangle))
    
        def step(self, action):
            state = self.canvas.coords(self.rectangle)
            base_action = np.array([0, 0])
            self.render()
    
            if action == 0:  # up
                if state[1] > UNIT:
                    base_action[1] -= UNIT
            elif action == 1:  # down
                if state[1] < (HEIGHT - 1) * UNIT:
                    base_action[1] += UNIT
            elif action == 2:  # left
                if state[0] > UNIT:
                    base_action[0] -= UNIT
            elif action == 3:  # right
                if state[0] < (WIDTH - 1) * UNIT:
                    base_action[0] += UNIT
    
            # 移动
            self.canvas.move(self.rectangle, base_action[0], base_action[1])
            self.canvas.tag_raise(self.rectangle)
            next_state = self.canvas.coords(self.rectangle)
            # 判断得分条件
            if next_state == self.canvas.coords(self.circle):
                reward = 100
                done = True
            elif next_state in [self.canvas.coords(self.triangle1),
                                self.canvas.coords(self.triangle2)]:
                reward = -100
                done = True
            else:
                reward = 0
                done = False
    
            next_state = self.coords_to_state(next_state)
            return next_state, reward, done
    
        # 渲染环境
        def render(self):
            time.sleep(0.03)
            self.update()
    
    展开全文
  • 在线Q绑在线查询源码带接口

    万次阅读 2021-04-15 16:11:46
    介绍: QQ绑定手机号查询源码 在线Q绑在线查询源码带接口 网盘下载地址: http://kekewl.cc/9vayoxPNGUg 图片:

    介绍:

    QQ绑定手机号查询源码 在线Q绑在线查询源码带接口


    网盘下载地址:

    http://kekewl.cc/9vayoxPNGUg


    图片:


    展开全文
  • A站、B站、C站、D站、E站、F站、G站、H站、I站、J站、K站、L站、M站、N站、O站、P站、Q站、R站、S站、T站、U站、V站、W站、X站、Y站、Z站都是什么网站? A站 https://www.acfun.cn/ AcFun弹幕视频网 - 认真你就输...

    A站、B站、C站、D站、E站、F站、G站、H站、I站、J站、K站、L站、M站、N站、O站、P站、Q站、R站、S站、T站、U站、V站、W站、X站、Y站、Z站都是什么网站?Q站是什么?

    A站、B站、C站、D站、E站、F站、G站、H站、I站、J站、K站、L站、M站、N站、O站、P站、Q站、R站、S站、T站、U站、V站、W站、X站、Y站、Z站都是什么网站?

    A站

    https://www.acfun.cn/

    AcFun弹幕视频网 - 认真你就输啦 (・ω・)ノ- ( ゜- ゜)つロ

    A站 AcFun ACG 弹幕 视频 动画 漫画 游戏 新番 鬼畜 东方 初音 DOTA MUGEN

    AcFun是国内首家弹幕视频网站,这里有全网独家动漫新番, 友好的弹幕氛围,有趣的UP主,好玩有科技感的虚拟偶像,年轻人都在用。

     

    B站

    https://www.bilibili.com/

    哔哩哔哩 (゜-゜)つロ 干杯~-bilibili

    bilibili是国内知名的视频弹幕网站,这里有及时的动漫新番,活跃的ACG氛围,有创意的Up主。大家可以在这里找到许多欢乐。

    Bilibili,哔哩哔哩,哔哩哔哩动画,哔哩哔哩弹幕网,弹幕视频,B站,弹幕,字幕,AMV,MAD,MTV,ANIME,动漫,动漫音乐,游戏,游戏解说,二次元,游戏视频,ACG,galgame,动画,番组,新番,初音,洛天依,vocaloid,日本动漫,国产动漫,手机游戏,网络游戏,电子竞技,ACG燃曲,ACG神曲,追新番,新番动漫,新番吐槽,巡音,镜音双子,千本樱,初音MIKU,舞蹈MMD,MIKUMIKUDANCE,洛天依原创曲,洛天依翻唱曲,洛天依投食歌,洛天依MMD,vocaloid家族,OST,BGM,动漫歌曲,日本动漫音乐,宫崎骏动漫音乐,动漫音乐推荐,燃系mad,治愈系mad,MAD MOVIE,MAD高燃

     

    C站

    不详(请各位大佬评论区补充)

     

    D站

    貌似因侵权暂时已关闭(请各位大佬评论区补充)

     

    E站

    不详(请各位大佬评论区补充)

     

    F站

    不详(请各位大佬评论区补充)

     

    G站

    叽哩叽哩游戏网ACG(G站) – ACG爱好者聚集地

    叽哩叽哩(G站)为ACG爱好者提供最新最好玩的ACG资源下载,P站,pixiv图集下载,单机游戏下载,单机游戏资讯等精彩内容

    单机游戏,P站,pixiv,单机游戏推荐,ACG,ACG游戏下载,G站,二次元,galgame,叽哩叽哩游戏网

     

    H站

    哈哩哈哩-还是那个温馨小站(H站)

    哈哩哈哩让你爱不离手的温馨小站,这里有最新最全的动漫、剧集、影视等作品供您欣赏,还有最新鲜的资讯让你提前知晓世间动态,哈哩哈哩爱不离手。

     

    I站

    不详(请各位大佬评论区补充)

     

    J站

    不详(请各位大佬评论区补充)

     

    K站

    K站 - 次元街

     

    L站

    http://www.lqzhan.com/

    L站-乐Q站-乐Q导航网

    乐Q导航网是专注于网络技术相关行业网址导航,提供最新前沿it技术资源分享相关行业网站网址,一站式网络技术学习起点站,用心打造最实用的技术网站导航!

    L站,乐Q站,乐Q导航,乐Q导航网,导航,资源导航,影视导航,站长导航,网址大全,网址收录,网站收录

     

    M站

    猫耳FM_来自二次元的声音_( :3」∠)_M站

    M站(猫耳FM)是第一家弹幕音图站,同时也是中国声优基地,在这里可以听电台,音乐,翻唱,小说和广播剧,用二次元声音连接三次元.

    猫耳FM,有声漫画,广播剧,催眠,日抓,配音,翻唱,电台,铃声,3D音乐,新闻,声优

     

    N站

    不详(请各位大佬评论区补充)

     

    O站

    Orzice_冰尘网 - 您的二次元ACGN爱好者社区ヾ(◍°∇°◍)ノ゙(O站)

    Orzice_冰尘网简称“O站”,一个综合性的二次元ACGN爱好者社区,动漫美图,cosplay,漫展活动,300英雄等ACGN资源应有尽有。一起吐槽楼主,寻找好姬友一起分享二次元日常。

     

    P站

    http://www.pixiv.net/

    插画交流网站 | pixiv

    动漫,p站,pixiv,acg,二次元

    pixiv(P站)是最大的动漫资源分享平台,专为ACG爱好者收集海量最新最好玩的ACG资源下载,P站图集,pixiv图集下载,有意思的动漫资讯,乐翻天的ACGN幻想次元领域,让您流连忘返。

     

    Q站

    http://www.iqzhan.com/

    Q站-好东西不私藏 乐于分享-关注QQ最新动态,掌握QQ第一资讯,分享最具价值内容

    Q站资源网,是一家QQ技术网,涵盖了QQ活动网的所有QQ资源,每天免费分享大量QQ技术教程,致力建设最大的QQ技术网站!

    Q站,情话,情感,励志,资源网,QQ教程,QQ活动,QQ资源,免费源码,免费软件,情感语录

     

    R站

    R站|学习使我快乐! - 专注C4D三维|建模|渲染|后期|动效|绑定|产品|包装|动画|自由艺术|设计学习交流

     

    S站

    嘶哩嘶哩-萌导航_silisili.cc | 您的私人二次元导航姬

    嘶哩嘶哩萌导航是一个极简风格的二次元导航主页网站,简洁清新,轻快大方,在嘶哩嘶哩导航你可以自定义喜欢的背景,以及自由切换偏好的搜索引擎,获取更舒适便捷的上网体验!

    嘶哩嘶哩,嘶哩嘶哩萌导航,二次元导航,简约导航网站,无广告,自定义壁纸主页网站,网址导航,网站导航,自定义网址导航,S站灯塔,silisili

     

    T站

    不详(请各位大佬评论区补充)

     

    U站

    不详(请各位大佬评论区补充)

     

    V站

    不详(请各位大佬评论区补充)

     

    W站

    不详(请各位大佬评论区补充)

     

    X站

    不详(请各位大佬评论区补充)

     

    Y站

    不详(请各位大佬评论区补充)

     

    Z站

    不详(请各位大佬评论区补充)

     

     

    展开全文
  • 用Tensorflow基于Deep Q Learning DQN 玩Flappy Bird

    万次阅读 多人点赞 2016-03-22 00:11:57
    前言2013年DeepMind 在NIPS上发表Playing Atari with Deep Reinforcement Learning 一文,提出了DQN(Deep Q Network)算法,实现端到端学习玩Atari游戏,即只有像素输入,看着屏幕玩游戏。Deep Mind就凭借这个应用...

    前言

    2013年DeepMind 在NIPS上发表Playing Atari with Deep Reinforcement Learning 一文,提出了DQN(Deep Q Network)算法,实现端到端学习玩Atari游戏,即只有像素输入,看着屏幕玩游戏。Deep Mind就凭借这个应用以6亿美元被Google收购。由于DQN的开源,在github上涌现了大量各种版本的DQN程序。但大多是复现Atari的游戏,代码量很大,也不好理解。

    Flappy Bird是个极其简单又困难的游戏,风靡一时。在很早之前,就有人使用Q-Learning 算法来实现完Flappy Bird。http://sarvagyavaish.github.io/FlappyBirdRL/
    但是这个的实现是通过获取小鸟的具体位置信息来实现的。

    能否使用DQN来实现通过屏幕学习玩Flappy Bird是一个有意思的挑战。(话说本人和朋友在去年年底也考虑了这个idea,但当时由于不知道如何截取游戏屏幕只能使用具体位置来学习,不过其实也成功了)

    最近,github上有人放出使用DQN玩Flappy Bird的代码,https://github.com/yenchenlin1994/DeepLearningFlappyBird【1】
    该repo通过结合之前的repo成功实现了这个想法。这个repo对整个实现过程进行了较详细的分析,但是由于其DQN算法的代码基本采用别人的repo,代码较为混乱,不易理解。
    这里写图片描述
    为此,本人改写了一个版本https://github.com/songrotek/DRL-FlappyBird

    对DQN代码进行了重新改写。本质上对其做了类的封装,从而使代码更具通用性。可以方便移植到其他应用。

    当然,本文的目的是借Flappy Bird DQN这个代码来详细分析一下DQN算法极其使用。

    DQN 伪代码

    这个是NIPS13版本的伪代码:

    Initialize replay memory D to size N
    Initialize action-value function Q with random weights
    for episode = 1, M do
        Initialize state s_1
        for t = 1, T do
            With probability ϵ select random action a_t
            otherwise select a_t=max_a  Q($s_t$,a; $θ_i$)
            Execute action a_t in emulator and observe r_t and s_(t+1)
            Store transition (s_t,a_t,r_t,s_(t+1)) in D
            Sample a minibatch of transitions (s_j,a_j,r_j,s_(j+1)) from D
            Set y_j:=
                r_j for terminal s_(j+1)
                r_j+γ*max_(a^' )  Q(s_(j+1),a'; θ_i) for non-terminal s_(j+1)
            Perform a gradient step on (y_j-Q(s_j,a_j; θ_i))^2 with respect to θ
        end for
    end for

    基本的分析详见Paper Reading 1 - Playing Atari with Deep Reinforcement Learning
    基础知识详见Deep Reinforcement Learning 基础知识(DQN方面)

    本文主要从代码实现的角度来分析如何编写Flappy Bird DQN的代码

    编写FlappyBirdDQN.py

    首先,FlappyBird的游戏已经编写好,是现成的。提供了很简单的接口:

    nextObservation,reward,terminal = game.frame_step(action)

    即输入动作,输出执行完动作的屏幕截图,得到的反馈reward,以及游戏是否结束。

    那么,现在先把DQN想象为一个大脑,这里我们也用BrainDQN类来表示,这个类只需获取感知信息也就是上面说的观察(截图),反馈以及是否结束,然后输出动作即可。

    完美的代码封装应该是这样。具体DQN里面如何存储。如何训练是外部不关心的。
    因此,我们的FlappyBirdDQN代码只有如下这么短:

    # -------------------------
    # Project: Deep Q-Learning on Flappy Bird
    # Author: Flood Sung
    # Date: 2016.3.21
    # -------------------------
    
    import cv2
    import sys
    sys.path.append("game/")
    import wrapped_flappy_bird as game
    from BrainDQN import BrainDQN
    import numpy as np
    
    # preprocess raw image to 80*80 gray image
    def preprocess(observation):
        observation = cv2.cvtColor(cv2.resize(observation, (80, 80)), cv2.COLOR_BGR2GRAY)
        ret, observation = cv2.threshold(observation,1,255,cv2.THRESH_BINARY)
        return np.reshape(observation,(80,80,1))
    
    def playFlappyBird():
        # Step 1: init BrainDQN
        brain = BrainDQN()
        # Step 2: init Flappy Bird Game
        flappyBird = game.GameState()
        # Step 3: play game
        # Step 3.1: obtain init state
        action0 = np.array([1,0])  # do nothing
        observation0, reward0, terminal = flappyBird.frame_step(action0)
        observation0 = cv2.cvtColor(cv2.resize(observation0, (80, 80)), cv2.COLOR_BGR2GRAY)
        ret, observation0 = cv2.threshold(observation0,1,255,cv2.THRESH_BINARY)
        brain.setInitState(observation0)
    
        # Step 3.2: run the game
        while 1!= 0:
            action = brain.getAction()
            nextObservation,reward,terminal = flappyBird.frame_step(action)
            nextObservation = preprocess(nextObservation)
            brain.setPerception(nextObservation,action,reward,terminal)
    
    def main():
        playFlappyBird()
    
    if __name__ == '__main__':
        main()

    核心部分就在while循环里面,由于要讲图像转换为80x80的灰度图,因此,加了一个preprocess预处理函数。

    这里,显然只有有游戏引擎,换一个游戏是一样的写法,非常方便。

    接下来就是编写BrainDQN.py 我们的游戏大脑

    编写BrainDQN

    基本架构:

    class BrainDQN:
        def __init__(self):
            # init replay memory
            self.replayMemory = deque()
            # init Q network
            self.createQNetwork()
        def createQNetwork(self):
    
        def trainQNetwork(self):
    
        def setPerception(self,nextObservation,action,reward,terminal):
        def getAction(self):
        def setInitState(self,observation):

    基本的架构也就只需要上面这几个函数,其他的都是多余了,接下来就是编写每一部分的代码。

    CNN代码

    也就是createQNetwork部分,这里采用如下图的结构(转自【1】):
    这里写图片描述

    这里就不讲解整个流程了。主要是针对具体的输入类型和输出设计卷积和全连接层。

    代码如下:

        def createQNetwork(self):
            # network weights
            W_conv1 = self.weight_variable([8,8,4,32])
            b_conv1 = self.bias_variable([32])
    
            W_conv2 = self.weight_variable([4,4,32,64])
            b_conv2 = self.bias_variable([64])
    
            W_conv3 = self.weight_variable([3,3,64,64])
            b_conv3 = self.bias_variable([64])
    
            W_fc1 = self.weight_variable([1600,512])
            b_fc1 = self.bias_variable([512])
    
            W_fc2 = self.weight_variable([512,self.ACTION])
            b_fc2 = self.bias_variable([self.ACTION])
    
            # input layer
    
            self.stateInput = tf.placeholder("float",[None,80,80,4])
    
            # hidden layers
            h_conv1 = tf.nn.relu(self.conv2d(self.stateInput,W_conv1,4) + b_conv1)
            h_pool1 = self.max_pool_2x2(h_conv1)
    
            h_conv2 = tf.nn.relu(self.conv2d(h_pool1,W_conv2,2) + b_conv2)
    
            h_conv3 = tf.nn.relu(self.conv2d(h_conv2,W_conv3,1) + b_conv3)
    
            h_conv3_flat = tf.reshape(h_conv3,[-1,1600])
            h_fc1 = tf.nn.relu(tf.matmul(h_conv3_flat,W_fc1) + b_fc1)
    
            # Q Value layer
            self.QValue = tf.matmul(h_fc1,W_fc2) + b_fc2
    
            self.actionInput = tf.placeholder("float",[None,self.ACTION])
            self.yInput = tf.placeholder("float", [None]) 
            Q_action = tf.reduce_sum(tf.mul(self.QValue, self.actionInput), reduction_indices = 1)
            self.cost = tf.reduce_mean(tf.square(self.yInput - Q_action))
            self.trainStep = tf.train.AdamOptimizer(1e-6).minimize(self.cost)

    记住输出是Q值,关键要计算出cost,里面关键是计算Q_action的值,即该state和action下的Q值。由于actionInput是one hot vector的形式,因此tf.mul(self.QValue, self.actionInput)正好就是该action下的Q值。

    training 部分。

    这部分是代码的关键部分,主要是要计算y值,也就是target Q值。

        def trainQNetwork(self):
            # Step 1: obtain random minibatch from replay memory
            minibatch = random.sample(self.replayMemory,self.BATCH_SIZE)
            state_batch = [data[0] for data in minibatch]
            action_batch = [data[1] for data in minibatch]
            reward_batch = [data[2] for data in minibatch]
            nextState_batch = [data[3] for data in minibatch]
    
            # Step 2: calculate y 
            y_batch = []
            QValue_batch = self.QValue.eval(feed_dict={self.stateInput:nextState_batch})
            for i in range(0,self.BATCH_SIZE):
                terminal = minibatch[i][4]
                if terminal:
                    y_batch.append(reward_batch[i])
                else:
                    y_batch.append(reward_batch[i] + GAMMA * np.max(QValue_batch[i]))
    
            self.trainStep.run(feed_dict={
                self.yInput : y_batch,
                self.actionInput : action_batch,
                self.stateInput : state_batch
                })

    其他部分

    其他部分就比较容易了,这里直接贴出完整的代码:

    # -----------------------------
    # File: Deep Q-Learning Algorithm
    # Author: Flood Sung
    # Date: 2016.3.21
    # -----------------------------
    
    import tensorflow as tf 
    import numpy as np 
    import random
    from collections import deque 
    
    class BrainDQN:
    
        # Hyper Parameters:
        ACTION = 2
        FRAME_PER_ACTION = 1
        GAMMA = 0.99 # decay rate of past observations
        OBSERVE = 100000. # timesteps to observe before training
        EXPLORE = 150000. # frames over which to anneal epsilon
        FINAL_EPSILON = 0.0 # final value of epsilon
        INITIAL_EPSILON = 0.0 # starting value of epsilon
        REPLAY_MEMORY = 50000 # number of previous transitions to remember
        BATCH_SIZE = 32 # size of minibatch
    
        def __init__(self):
            # init replay memory
            self.replayMemory = deque()
            # init Q network
            self.createQNetwork()
            # init some parameters
            self.timeStep = 0
            self.epsilon = self.INITIAL_EPSILON
    
        def createQNetwork(self):
            # network weights
            W_conv1 = self.weight_variable([8,8,4,32])
            b_conv1 = self.bias_variable([32])
    
            W_conv2 = self.weight_variable([4,4,32,64])
            b_conv2 = self.bias_variable([64])
    
            W_conv3 = self.weight_variable([3,3,64,64])
            b_conv3 = self.bias_variable([64])
    
            W_fc1 = self.weight_variable([1600,512])
            b_fc1 = self.bias_variable([512])
    
            W_fc2 = self.weight_variable([512,self.ACTION])
            b_fc2 = self.bias_variable([self.ACTION])
    
            # input layer
    
            self.stateInput = tf.placeholder("float",[None,80,80,4])
    
            # hidden layers
            h_conv1 = tf.nn.relu(self.conv2d(self.stateInput,W_conv1,4) + b_conv1)
            h_pool1 = self.max_pool_2x2(h_conv1)
    
            h_conv2 = tf.nn.relu(self.conv2d(h_pool1,W_conv2,2) + b_conv2)
    
            h_conv3 = tf.nn.relu(self.conv2d(h_conv2,W_conv3,1) + b_conv3)
    
            h_conv3_flat = tf.reshape(h_conv3,[-1,1600])
            h_fc1 = tf.nn.relu(tf.matmul(h_conv3_flat,W_fc1) + b_fc1)
    
            # Q Value layer
            self.QValue = tf.matmul(h_fc1,W_fc2) + b_fc2
    
            self.actionInput = tf.placeholder("float",[None,self.ACTION])
            self.yInput = tf.placeholder("float", [None]) 
            Q_action = tf.reduce_sum(tf.mul(self.QValue, self.actionInput), reduction_indices = 1)
            self.cost = tf.reduce_mean(tf.square(self.yInput - Q_action))
            self.trainStep = tf.train.AdamOptimizer(1e-6).minimize(self.cost)
    
            # saving and loading networks
            saver = tf.train.Saver()
            self.session = tf.InteractiveSession()
            self.session.run(tf.initialize_all_variables())
            checkpoint = tf.train.get_checkpoint_state("saved_networks")
            if checkpoint and checkpoint.model_checkpoint_path:
                    saver.restore(self.session, checkpoint.model_checkpoint_path)
                    print "Successfully loaded:", checkpoint.model_checkpoint_path
            else:
                    print "Could not find old network weights"
    
        def trainQNetwork(self):
            # Step 1: obtain random minibatch from replay memory
            minibatch = random.sample(self.replayMemory,self.BATCH_SIZE)
            state_batch = [data[0] for data in minibatch]
            action_batch = [data[1] for data in minibatch]
            reward_batch = [data[2] for data in minibatch]
            nextState_batch = [data[3] for data in minibatch]
    
            # Step 2: calculate y 
            y_batch = []
            QValue_batch = self.QValue.eval(feed_dict={self.stateInput:nextState_batch})
            for i in range(0,self.BATCH_SIZE):
                terminal = minibatch[i][4]
                if terminal:
                    y_batch.append(reward_batch[i])
                else:
                    y_batch.append(reward_batch[i] + GAMMA * np.max(QValue_batch[i]))
    
            self.trainStep.run(feed_dict={
                self.yInput : y_batch,
                self.actionInput : action_batch,
                self.stateInput : state_batch
                })
    
            # save network every 100000 iteration
            if self.timeStep % 10000 == 0:
                saver.save(self.session, 'saved_networks/' + 'network' + '-dqn', global_step = self.timeStep)
    
    
        def setPerception(self,nextObservation,action,reward,terminal):
            newState = np.append(nextObservation,self.currentState[:,:,1:],axis = 2)
            self.replayMemory.append((self.currentState,action,reward,newState,terminal))
            if len(self.replayMemory) > self.REPLAY_MEMORY:
                self.replayMemory.popleft()
            if self.timeStep > self.OBSERVE:
                # Train the network
                self.trainQNetwork()
    
            self.currentState = newState
            self.timeStep += 1
    
        def getAction(self):
            QValue = self.QValue.eval(feed_dict= {self.stateInput:[self.currentState]})[0]
            action = np.zeros(self.ACTION)
            action_index = 0
            if self.timeStep % self.FRAME_PER_ACTION == 0:
                if random.random() <= self.epsilon:
                    action_index = random.randrange(self.ACTION)
                    action[action_index] = 1
                else:
                    action_index = np.argmax(QValue)
                    action[action_index] = 1
            else:
                action[0] = 1 # do nothing
    
            # change episilon
            if self.epsilon > self.FINAL_EPSILON and self.timeStep > self.OBSERVE:
                self.epsilon -= (self.INITIAL_EPSILON - self.FINAL_EPSILON)/self.EXPLORE
    
            return action
    
        def setInitState(self,observation):
            self.currentState = np.stack((observation, observation, observation, observation), axis = 2)
    
        def weight_variable(self,shape):
            initial = tf.truncated_normal(shape, stddev = 0.01)
            return tf.Variable(initial)
    
        def bias_variable(self,shape):
            initial = tf.constant(0.01, shape = shape)
            return tf.Variable(initial)
    
        def conv2d(self,x, W, stride):
            return tf.nn.conv2d(x, W, strides = [1, stride, stride, 1], padding = "SAME")
    
        def max_pool_2x2(self,x):
            return tf.nn.max_pool(x, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = "SAME")
    
    

    一共也只有160代码。
    如果这个任务不使用深度学习,而是人工的从图像中找到小鸟,然后计算小鸟的轨迹,然后计算出应该怎么按键,那么代码没有好几千行是不可能的。深度学习大大减少了代码工作。

    小结

    本文从代码角度对于DQN做了一定的分析,对于DQN的应用,大家可以在此基础上做各种尝试。

    展开全文
  • 谐振电路Q值的意义

    千次阅读 2020-06-03 15:14:04
    1、Q值等于谐振电路中存储能量与每个周期内消耗的能量的2π倍,Q值越大,意味着相对于存储的能量来说所需付出的能量耗散约束,即谐振电路储能的效率越高; Q=2πWS/WRQ=2π W_S/W_R Q=2πWS​/WR​ 2、谐振电路的通...
  • 关于电感的Q

    千次阅读 2018-11-12 18:51:49
    关于电感的Q值   什么是电感的Q值?关于电感的Q值,品质因数    Q值;是衡量电感器件的主要参数。是指电感器在某一频率的交流电压下工作时,所呈现的感抗与其等效损耗电阻之比。电感器的Q值越高,其损耗越小,...
  • Q插件签到

    千次下载 热门讨论 2012-11-15 13:20:43
    插件酷Q插件签到
  • C++中是没有像其他后辈(C# Java)那样,提供枚举变量到字符串之间的快捷转换功能的,程序要打印枚举变量时,只能额外再写一个转换函数,费时费力,好在,Qt提供了这个功能,通过Q_ENUM宏和Q_FLAG宏,实现了更多更酷...
  • 如何画出比别人灵动的Q版人物?怎样才能画好Q版人物动作?画好Q版人物动作有哪些技巧?想必这些问题都是绘画初学者们比较伤脑筋的问题,那么到底怎样才能画好动漫Q版人物动作呢?今天灵猫课堂老师就在网络上收集整理...
  • 本文是对 http://mnemstudio.org/path-finding-q-learning-tutorial.htm 的翻译,共分两部分,第一部分为中文翻译,第二部分为英文原文。...这篇教程通俗易懂,是学习理解 Q-learning 算法工作原理的绝佳入门材料。
  • Q学习(Q-learning)入门小例子及python实现

    万次阅读 多人点赞 2019-09-24 18:13:09
    一、从马尔科夫过程到Q学习 # 有一定基础的读者可以直接看第二部分 Q学习(Q-learning)算法是一种与模型无关的强化学习算法,以马尔科夫决策过程(Markov Decision Processes, MDPs)为理论基础。 标准的...
  • w25q128fv中文手册 w25q256fv中文手册

    热门讨论 2015-07-01 20:11:35
    w25q128fv中文手册 w25q256fv中文手册 256可以参考128的 完全中文手册
  • 散点图和q-q

    千次阅读 2019-06-18 13:25:43
    绘制散点图和q-q图: import numpy as np import matplotlib.pyplot as plt from scipy import stats age = [23,23,27,27,39,41,47,49,50,52,54,54,56,57,58,58,61] fat = [9.5,26.5,7.8,17.8,31.4,25.9,27.4,27.2,...
  • 三极管的Q点/静态工作点

    万次阅读 2018-07-06 10:59:38
    三极管的Q点/静态工作点浅谈  晶体三极管静态工作点的设置而所谓谓静态工作点是指放大电路在没有交流信号输人的情况下,三极管处于直流工作状态。其各极电压和电流都处于一个恒定值,即处于相对“静止”的状态,故...
  • Q学习和深度Q学习(DQN)论文笔记

    万次阅读 多人点赞 2019-01-02 15:20:46
    Q学习(Q-learning) ...Qπ(st,at)=E[r+γE[Qπ(st+1,at+1)]]Q^\pi(s_t,a_t)=E[r+\gamma E[Q^\pi(s_{t+1},a_{t+1})]]Qπ(st​,at​)=E[r+γE[Qπ(st+1​,at+1​)]] 这个公式实际上也揭露了状态的马尔科夫性质,也...
  • 电容Q值和D值

    千次阅读 2016-09-28 10:41:33
    在做射频的时候,选择电感电容时特别关注他们的Q值,那什么是Q值呢,正好有人问,就分享下吧,怕自己说的太简单,在网上找了个专业点的。 Q值是什么意思,它为什么重要? 品质因数Q:表征一个储能器件(如电感线圈、...
  • 深度解读Q_D指针与Q_Q指针

    千次阅读 2018-03-29 11:34:13
    首先是Q_D指针:先贴上我们的测试用例.class TEST; class TESTPrivate { public: TESTPrivate(TEST *parent):q_ptr(parent),a(666) {cout &lt;&lt; "TESTPrivate" &lt;&lt; endl;} ~...
  • 解读 Q_D, Q_Q 指针

    千次阅读 2014-03-27 15:21:32
    见 qglog.h文件定义:  ... #define Q_Q(Class) Class * const q = q_func()   d指针是在主类中使用的,来获取私有子类成员指针   q指针是在私有数据类中使用的,来获取主类对象指针 D-指针   私
  • 总算明白了Q-Q plot

    万次阅读 2018-09-13 16:47:11
    Q代表quantile,图上的每一个点有个内在属性,就是两组数据的分位点是相同的;比如说某个点是数据集1的上四分位点,那么也一定是数据集2的上四分位点; The quantile-quantile (q-q) plot is a graphical technique ...
  • 滤波器的Q值到底是什么鬼?

    万次阅读 2018-05-22 15:40:03
    滤波器的QQ值对实际滤波效果影响倒不大,但Q值代表的是损耗 / 输入功率,Q值越高,说明损耗越大,意指会有部分能量在滤波器的电感上被损耗掉。在一般的低功率电源滤波器和信号滤波器上,此问题不会太突出。但在较...
  • p->next=qq=p->next区分

    万次阅读 多人点赞 2019-05-19 22:14:43
    p->next=qq 赋值给p->next,即p的下一个结点是q q=p->next 将p->next(t)赋值给q, 即q也指向t
  • W25Q128BV W25Q128FV W25Q128JV 什么区别?

    千次阅读 2019-01-19 19:10:00
    W25Q128BV W25Q128FV W25Q128JV 什么区别?  官网没有找到 BV 的相关信息, 倒是有 FV,FW,JV,JW 信息。。2019年1月19日19:09:55  FV / JV 的区别是 速度的区别。104MHz/133MHz. 转载于:...
  • Django Q查询

    千次阅读 2019-09-06 14:46:43
    1、导入Q对象 from django.db.model import Q Q 对象可以使用c&(AND)和|(OR)操作符组合起来。 当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。 2、例子 Q(question__startswith='Who') | Q...
  • Q_ENUM与Q_ENUMS的区别

    千次阅读 2019-05-28 08:52:01
    Q_ENUMS: This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. This macro registers one or several enum types to the meta-object...
  • Android Q 不叫 Q,正式命名为 Android 10

    千次阅读 2019-08-24 15:28:04
    根据官方博文,谷歌已经公布了 Android Q 的名称,它并不像以前一样,以甜食命名,也不是以任何以字母 Q 开头来命名,而是简单称它为 Android 10。 该公司表示,正在改变其发布版本的命名方式。该公司写道: 这些...
  • Android Q隐私权:权限变更 本文档介绍了权限模型的一些变更。这些变更有助于增强用户隐私。 其中一些变更会影响在Android Q上运行的所有应用,而其他变更仅会影响以Android Q为目标平台的应用。 影响所有应用的...
  • nodejs q模块

    万次阅读 2016-05-15 22:10:37
    nodejs module q q模块 promise q模块的安装 promise的使用 then 函数 流式操作 组合操作 Promise的创建 Using Qfcall Using Deferreds Using QPromise 实际例子 测试服务器 并行请求 串行请求 延时操作 接触nodejs...
  • smith 图中Q值和阻抗匹配

    千次阅读 2016-09-05 14:11:18
    阻抗匹配的线越靠近实轴q值就越小,远离就越大 Q=阻抗的虚部除以实部
  • 前期回顾 强化学习经典算法笔记(零):贝尔曼方程的推导 强化学习经典算法笔记(一):价值迭代算法Value Iteration ...强化学习经典算法笔记(四):时间差分算法Temporal Difference(Q-Learning算法) 强化学习经典算...
  • 【强化学习】Deep Q Network(DQN)算法详解

    万次阅读 多人点赞 2018-06-20 11:45:30
    DQN(Deep Q-Learning)是将深度学习deeplearning与强化学习reinforcementlearning相结合,实现了从感知到动作的端到端的革命性算法。使用DQN玩游戏的话简直6的飞起,其中fladdy bird这个游戏就已经被DQN玩坏了。当...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,424,861
精华内容 969,944
关键字:

q