2022暑假强化学习记录

前言

强化学习可以来帮助我们进行辅助决策,例如根据当前的游戏场景,自动帮我们"按下"相应按键自个儿玩游戏。例如让AI从头自学开车(基于Deep-Q-Learning强化学习)
个人觉得强化学习的基础稍微需要靠一点数学。
本文章是学习 俞勇《动手学强化学习》这本书的记录。
github代码链接: https://github.com/boyu-ai/Hands-on-RL
课程链接: 伯禹学习平台-动手学强化学习




另外,我觉得还可以看看这个 强化学习第一节(RL基本概念+工具+基本算法 等接下来的一系列教程, 例如后面的DQN算法部分讲得似乎很详细。
看完文末代码实践的例子后,推荐看看这篇我另外一篇博客 强化学习_蒙特卡罗与时序差分(Sarsa/Q-Learning)例子

另外,这本蘑菇书也不错 蘑菇书EasyRL, 想配套的github链接: datawhalechina/easy-rl



其他推荐

可以看看这个, https://github.com/kzl/decision-transformer



内容笔记

基础知识

强化学习简介

1.价值函数是对于 未来累积奖励 的预测,评估给定策略下 状态 的好坏。
2.基于模型 的强化学习和 模型无关 的强化学习的根本区别在于学习过程中有没有环境模型。


探索与利用

1.在策略学习过程中,往往需要进行新策略探索与旧策略的利用, 以实现 尝试不同策略,以进行策略提升/提升对旧策略的评估能力
2. ϵ-greedy算法 不具有 次线性收敛保证, 衰减ϵ-greedy算法 才具有次线性收敛保证


马尔科夫决策过程

1.马尔科夫决策过程(Markov decision process, MDP)可以由状态集合、动作集合、状态转移概率、折扣因子、奖励函数构成的五元组表示。
2.马尔科夫决策过程
   ~~   数学特性:提供了一套结果部分随机、部分在决策者的控制下的决策过程建模的数学框架
   ~~   状态的性质:从历史中捕获所有相关信息 ;
   ~~   对于强化学习的意义:形式化地描述了一种强化学习的环境 ;
3.马尔科夫决策过程的当前状态是未来的充分统计量。
4.马尔科夫性质: 当前状态可以完全表征过程。


基于动态规划的强化学习

1.价值迭代贪心 更新法
2.策略迭代中,用 Bellman等式 更新价值函数代价很大。
3.策略迭代 更适合 空间较小 的马尔科夫决策过程, 价值迭代 更适合 空间较大 的马尔科夫决策过程。
4.MDP(马尔科夫决策过程)的目标是选择可以最大化 累积奖励期望 的动作。
5.达成MDP目标的方法是可以对 最优价值函数最优策略 执行迭代更新。
6.价值迭代使用 Bellman等式 对价值函数进行迭代更新
V ( s ) = R ( s ) + m a x α ∈ A γ ∑ s ′ ∈ S P s α ( s ′ ) V ( s ′ ) V(s) = R(s)+max_{\alpha \in A \gamma} \sum_{s'\in S}P_{s\alpha }(s')V(s') V(s)=R(s)+maxαAγsSPsα(s)V(s)


基于模型的强化学习

学习一个MDP模型主要是学习 状态转移概率奖励函数
2.从经验中直接学习价值函数和策略叫做 模型无关 的强化学习。(注意,这里的模型指的是环境,在强化学习中,负责决策的一般叫智能体agent)


蒙特卡洛价值预测

1.蒙特卡洛策略评估使用 经验平均累计 奖励
2.蒙特卡洛是一种 off-line 的方法, 它的更新策略:
V ( S t ) = V ( S t ) + α ( G t ( n ) − V ( S t ) ) V(S_t) = V(S_t)+\alpha (G_t^{(n)}-V(S_t)) V(St)=V(St)+α(Gt(n)V(St))


模型无关控制方法

1.ϵ贪心策略探索中,以 1-ϵ 的概率选择 贪心策略, ϵ 的概率 随机 选择策略。
2.时序差分学习是 在线策略 算法、可以基于 不完整 的序列进行、具有更低的方差、有偏估计的特点。
3.模型无关的强化学习可以被分为两类,在线策略学习 和 离线策略学习。


重要性采样

1.离线策略蒙特卡洛根据两个策略之间的 重要性比 对累计奖励 G t G_t Gt 加权


时序差分

1.时序差分 方法直接从经验片段中进行学习、结合了 动态规划蒙特卡洛 方法的思想、能够从不完整的序列中学习、方差有偏差。Sarse算法和Q-Learning算法都属于时序差分算法。
2.时序差分的目标是 R t + 1 + γ V ( S t + 1 ) R_{t+1}+\gamma V(S_{t+1}) Rt+1+γV(St+1).
3.蒙特卡洛必须等 片段结束,直到累计奖励已知、只能从完整序列 中学习、只能在 片段化有终止 的环境下工作、具有 高方差无偏差 的特点。
4.时序差分的目标 R t + 1 + γ V ( S t + 1 ) R_{t+1} + \gamma V(S_{t+1}) Rt+1+γV(St+1) V π ( S t ) V^\pi (S_t) Vπ(St) 的有偏估计,而时序差分的真实目标 R t + 1 + γ V π ( S t + 1 ) R_{t+1} + \gamma V^\pi (S_{t+1}) Rt+1+γVπ(St+1) 才是 V π ( S t ) V^\pi (S_t) Vπ(St) 的无偏估计。
5.时序差分算法是一种 on-line方法, 它的更新:
V ( S t ) = V ( S t ) + α ( R t + 1 + γ V ( S t + 1 ) − V ( S t ) ) V(S_t) = V(S_t)+\alpha (R_{t+1}+\gamma V(S_{t+1})-V(S_t)) V(St)=V(St)+α(Rt+1+γV(St+1)V(St))


Sarsa算法

1.SARSA是一种 在线策略(on-policy)算法, SARSA算法中的两个“A”都是由当前策略选择的。
2.SARSA算法通常使用 ϵ-贪心 策略进行策略评估和改进。
3. SARSA算法更新:
Q ( S t , A t ) = Q ( S t , A t ) + α [ R t + 1 + γ Q ( S t + 1 , A t + 1 ) − Q ( S t , A t ) ] Q(S_t, A_t) = Q(S_t, A_t) + \alpha[R_{t+1}+\gamma Q(S_{t+1}, A_{t+1})-Q(S_t, A_t)] Q(St,At)=Q(St,At)+α[Rt+1+γQ(St+1,At+1)Q(St,At)]


Q-learning

1.Q学习是一种 离线策略 学习方法,探索策略与优化策略不是同一个。
2.Q学习 不需要重要性采样 ,采用 多步自助法 时需要。
3.Q学习算法更新:
Q ( S t , A t ) = Q ( S t , A t ) + α [ R t + 1 + γ m a x α Q ( S t + 1 , α ) − Q ( S t , A t ) ] Q(S_t, A_t) = Q(S_t, A_t) + \alpha[R_{t+1}+\gamma max_\alpha Q(S_{t+1}, \alpha)-Q(S_t, A_t)] Q(St,At)=Q(St,At)+α[Rt+1+γmaxαQ(St+1,α)Q(St,At)]



价值函数近似算法

1.在更新状态值函数近似的参数θ时, θ − > θ + α ( V π ( s ) − V θ ( s ) ) x ( s ) \theta -> \theta+\alpha(V^\pi (s)-V_{\theta}(s))x(s) θ>θ+α(Vπ(s)Vθ(s))x(s),其中 α \alpha α表示步长, V π ( s ) − V θ ( s ) V^\pi (s)-V_{\theta}(s) Vπ(s)Vθ(s)表示预测误差, x ( s ) x(s) x(s)表示特征值。


深度强化学习

深度强化学习简介

1.深度强化学习的思想是直接使用 深度神经网络 建立 价值策略 近似函数
2.深度强化学习可以分类为基于 价值 的方法、基于 随机策略 的方法和基于 确定性策略 的方法,其中基于确定性策略的方法包括了 确定性策略梯度(DPG)和 深度确定性策略梯度(DDPG)。


DQN

1.利用 神经网络 去预测 当前状态下的Q函数。通过输出层神经元最大的Q函数值选择相应的action。
2.特点:
   ~~   (1).分为policy network和target network, 让训练更稳定
   ~~   (2).replay memory, 可以提高数据使用率,减少样本间的相关性,减轻单一序列导致的波动,稳定训练效果。

截图来自: 强化学习第五节(DQN)

45:59时刻
2022暑假强化学习记录_第1张图片

1:00:21时刻
2022暑假强化学习记录_第2张图片


代码实战例子

蛇棋

代码讲解bilibili
代码来源: desny/snake_and_ladders

引入一些库

import numpy as np
import gym
from gym.spaces import Discrete

from contextlib import contextmanager
import time

@contextmanager
def timer(name):
    start = time.time()
    yield
    end = time.time()
    print('{} COST:{}'.format(name, end-start))



构建蛇棋环境

Discrete是 gym库中一个类。
Discrete(2) # {0, 1}
Discrete(3, start=-1) # {-1, 0, 1}

class SnakeEnv(gym.Env):
    SIZE=100
    
    def __init__(self, ladder_num, dices):
        self.ladder_num = ladder_num
        self.dices = dices
        self.observation_space = Discrete(self.SIZE+1)
        self.action_space = Discrete(len(dices))
        
        if ladder_num == 0:
            self.ladders = {0:0}
        else:
            # 处理梯子值,让梯子的数值无重复地反向赋值
            ladders = set(np.random.randint(1, self.SIZE, size=self.ladder_num*2))
            while len(ladders) < self.ladder_num*2:
                ladders.add(np.random.randint(1, self.SIZE))

            ladders = list(ladders)
            ladders = np.array(ladders)
            np.random.shuffle(ladders)
            ladders = ladders.reshape((self.ladder_num,2))

            re_ladders = list()
            for i in ladders:
                re_ladders.append([i[1],i[0]])

            re_ladders = np.array(re_ladders)
            # dict()可以把nx2维数组转化为字典形式
            self.ladders = dict(np.append(re_ladders, ladders, axis=0))
        print(f'ladders info:{self.ladders} dice ranges:{self.dices}')
        self.pos = 1
        
    def reset(self):
        self.pos = 1
        return self.pos
    
    def step(self, a):
        step = np.random.randint(1, self.dices[a]+1)
        self.pos += step
        if self.pos == 100:
            return 100, 100, 1, {}
        elif self.pos > 100:
            self.pos = 200 - self.pos
            
        if self.pos in self.ladders:
            self.pos = self.ladders[self.pos]
        return self.pos, -1, 0, {}
    
    def reward(self, s):
        if s == 100:
            return 100
        else:
            return -1
    
    # 无渲染
    def render(self):
        pass



构建智能体

主要是奖励r, 策略pi, 转移概率p

class TableAgent(object):
    def __init__(self, env):
        self.s_len = env.observation_space.n
        self.a_len = env.action_space.n
        
        self.r = [env.reward(s) for s in range(0, self.s_len)]
        # 确定性策略
        self.pi = np.zeros(self.s_len, dtype=int)
        # A x S x S
        self.p = np.zeros([self.a_len, self.s_len, self.s_len], dtype=float)
        
        # 函数参数向量化,参数可以传入列表
        ladder_move = np.vectorize(lambda x: env.ladders[x] if x in env.ladders else x)
        
        # based-model 初始化表格所有位置的概率p[A,S,S]
        for i, dice in enumerate(env.dices):
            prob = 1.0 / dice
            for src in range(1, 100):
                # 因为arange只给一个数字的时候,是从0开始取到end-1,所以在此处+1
                step = np.arange(dice) + 1
                step += src
                step = np.piecewise(step, [step>100, step<=100], [lambda x: 200-x, lambda x: x])
                step = ladder_move(step)
                for dst in step:
                    # 在当前位置pos=src的情况下,采取i投掷色子的方式,得到最终位置dst
                    # 概率直接求和的方式是否合理?
                    self.p[i, src, dst] += prob
        
        # 因为src最多到99,所以p[:, 100, 100]是0,此处进行填补
        self.p[:, 100, 100] = 1
        self.value_pi = np.zeros((self.s_len))
        self.value_q = np.zeros((self.s_len, self.a_len))
        self.gamma = 0.8
        
        
    def play(self, state):
        return self.pi[state]



策略评估(通过计算reward)

def eval_game(env, agent):
    state = env.reset()
    total_reward = 0
    state_action = []
    
    while True:
        act = agent.play(state)
        state_action.append((state,act))
        state, reward, done, _ = env.step(act)
        total_reward += reward
        if done:
            break
    
    return total_reward, state_action



算法部分, 这里实现三种迭代算法,分别是策略迭代算法、价值迭算法和泛化迭代算法。

策略迭代算法

2022暑假强化学习记录_第3张图片

注意:图片来源于网上,仅用于学习,请勿恶意传播。截图来源: https://www.bilibili.com/video/BV1VY411W7Mm/?p=2

class PolicyIteration(object):
    
    dice = [3,6]
    
    def policy_evaluation(self, agent, max_iter=-1):
        iteration = 0
        while True:
            iteration += 1
            new_value_pi = agent.value_pi.copy()
            # 遍历所有的state 1~100  (s.len=101)
            for i in range(1, agent.s_len):
                ac = agent.pi[i]
                
                for j in range(0, agent.a_len):
                    # 选择确定性策略的action
                    if ac != j:
                        continue
                    transition = agent.p[ac, i, :]
                    value_sa = np.dot(transition, agent.r + agent.gamma * agent.value_pi)
                    # 放在j循环外部会报错:UnboundLocalError 因为跳过action无法算value_sa的值。
                    # 未求得value_sa就用该值就会报错(UnboundLocalError)
                    new_value_pi[i] = value_sa
            
            diff = np.sqrt(np.sum(np.power(agent.value_pi - new_value_pi, 2)))
            # 判断是否收敛
            if diff < 1e-6:
                print('policy evaluation proceed {} iters.'.format(iteration))
                break
            else:
                agent.value_pi = new_value_pi
            if iteration == max_iter:
                print('policy evaluation proceed {} iters.'.format(iteration))
                break
    
    
    def policy_improvement(self, agent):
        new_policy = np.zeros_like(agent.pi)
        for i in range(1, agent.s_len):
            for j in range(0, agent.a_len):
                transition = agent.p[j, i, :]
                agent.value_q[i,j] = np.dot(transition, agent.r + agent.gamma * agent.value_pi)
            # update policy
            max_act = np.argmax(agent.value_q[i,:])
            # 选择使value_q最大的action
            new_policy[i] = max_act
        
        # 如果没有更新(新策略和旧策略一致),返回False;如果不相等就赋值新策略/优化策略后,返回True
        if np.all(np.equal(new_policy, agent.pi)):
            return False
        else:
            agent.pi = new_policy
            return True
    
    
    def policy_iteration(self, agent, max_iter=-1):
        iteration = 0
        with timer('Timer PolicyIter'):
            while True:
                iteration += 1
                with timer('Timer PolicyEval'):
                    # 通过迭代求得agent.value_pi 准确估计值函数
                    self.policy_evaluation(agent, max_iter)
                with timer('Timer PolicyImprove'):
                    # 获得最优策略
                    ret = self.policy_improvement(agent)
                if not ret:
                    break
        print('Iter {} rounds converge'.format(iteration))



运行 策略迭代 的函数(就是上述实现的 策略迭代算法)。

def policy_iteration_demo(env):
    agent = TableAgent(env)
    pi_algo = PolicyIteration()
    pi_algo.policy_iteration(agent)
    print('agent.pi={}'.format(agent.pi))
    total_reward, state_action = eval_game(env, agent)
    print('total_reward={0}, state_action={1}'.format(total_reward, state_action))



价值迭代算法

2022暑假强化学习记录_第4张图片

注意:图片来源于网上,仅用于学习,请勿恶意传播。截图来源: https://www.bilibili.com/video/BV1VY411W7Mm/?p=2

def value_iteration(agent, max_iter=-1):
        iteration = 0
        dice = [3,6]
        with timer('Timer ValueIter'):
            while True:
                iteration += 1
                new_value_pi = agent.value_pi.copy()
                for i in range(1, agent.s_len):
                    value_sas = []
                    for j in range(0, agent.a_len):
                        value_sa = np.dot(agent.p[j,i,:], agent.r + agent.gamma * agent.value_pi)
                        value_sas.append(value_sa)
                    new_value_pi[i] = max(value_sas)

                diff = np.sqrt(np.sum(np.power(agent.value_pi - new_value_pi, 2)))
                if diff < 1e-6:
                    break
                else:
                    agent.value_pi = new_value_pi
                if iteration == max_iter:
                    break
            print('Iter {} rounds converge'.format(iteration))
            for i in range(1, agent.s_len):
                for j in range(0, agent.a_len):
                    agent.value_q[i,j] = np.dot(agent.p[j,i,:], agent.r + agent.gamma * agent.value_pi)
                max_act = np.argmax(agent.value_q[i,:])
                agent.pi[i] = max_act



对比运行上面两种迭代算法(策略迭代和价值迭代)的时间和reward。

# 价值迭代和策略迭代的对比
def policy_vs_value_demo(env):
    policy_agent = TableAgent(env)
    value_agent = TableAgent(env)
    
    pi_algo = PolicyIteration()
    pi_algo.policy_iteration(policy_agent)
    print('agent.pi={}'.format(policy_agent.pi))
    total_reward, state_action = eval_game(env, policy_agent)
    print('total_reward={0}, state_action={1}'.format(total_reward, state_action))
    
    value_iteration(value_agent)
    print('agent.pi={}'.format(value_agent.pi))
    total_reward, state_action = eval_game(env, value_agent)
    print('total_reward={0}, state_action={1}'.format(total_reward, state_action))



泛化迭代

泛化迭代 = 价值迭代 + 策略迭代 (先让值函数 V π ( s ) V_{\pi}(s) Vπ(s)最优,再用值函数进行策略改进)
下面代码进行泛化迭代,同时对比前面两种算法。

# 泛化迭代和前两种迭代的对比
def generalized_policy_compare(env):
    policy_vs_value_demo(env)
    
    gener_agent = TableAgent(env)
    
    with timer('Timer GeneralizedIter'):
        value_iteration(gener_agent, 10)
        pi_algo = PolicyIteration()
        pi_algo.policy_iteration(gener_agent, 1)
    print('agent.pi={}'.format(gener_agent.pi))
    total_reward, state_action = eval_game(env, gener_agent)
    print('total_reward={0}, state_action={1}'.format(total_reward, state_action))



主入口

if __name__ == '__main__':
    # 策略迭代  两个demo梯子数不同
    # env1 = SnakeEnv(0,[3,6])
    env2 = SnakeEnv(10,[3,6])
    # policy_iteration_demo(env1)
    # policy_iteration_demo(env2)
    
    # 价值迭代和策略迭代的对比
    # policy_vs_value_demo(env2)
    
    # 泛化迭代
    generalized_policy_compare(env2)

输出:

Output exceeds the size limit. Open the full output data in a text editor
ladders info:{90: 91, 22: 73, 8: 28, 5: 92, 27: 78, 34: 42, 50: 64, 44: 21, 37: 98, 77: 79, 91: 90, 73: 22, 28: 8, 92: 5, 78: 27, 42: 34, 64: 50, 21: 44, 98: 37, 79: 77} dice ranges:[3, 6]
policy evaluation proceed 93 iters.
Timer PolicyEval COST:0.09976077079772949
Timer PolicyImprove COST:0.002475261688232422
policy evaluation proceed 71 iters.
Timer PolicyEval COST:0.0747995376586914
Timer PolicyImprove COST:0.0029921531677246094
policy evaluation proceed 60 iters.
Timer PolicyEval COST:0.06582498550415039
Timer PolicyImprove COST:0.00299072265625
Timer PolicyIter COST:0.24884343147277832
Iter 3 rounds converge
agent.pi=[0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
 1 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 0 0 0 0]
total_reward=92, state_action=[(1, 1), (2, 0), (4, 0), (6, 0), (7, 0), (28, 0), (29, 0), (32, 1), (98, 0)]
Iter 94 rounds converge
Timer ValueIter COST:0.1904895305633545
agent.pi=[0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0
 1 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 0 0 0 0]
total_reward=88, state_action=[(1, 1), (7, 0), (10, 1), (11, 1), (16, 1), (20, 1), (23, 0), (25, 1), (29, 0), (32, 1), (98, 0), (99, 0), (99, 0)]
Iter 10 rounds converge
Timer ValueIter COST:0.02293848991394043
policy evaluation proceed 1 iters.
...
agent.pi=[0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0 0 1 1 1 0 0 0
 1 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 0 0 0 0]
total_reward=93, state_action=[(1, 1), (3, 0), (92, 0), (95, 1), (99, 0), (99, 0), (99, 0), (99, 0)]

你可能感兴趣的:(人工智能,强化学习,reinforcement,RL)