(5-2)时序差分学习和SARSA算法:SARSA算法

SARSA(State-Action-Reward-State-Action)是一种强化学习算法,用于解决马尔可夫决策过程(MDP)中的控制问题,即学习一个最优策略来最大化累积奖励。

5.2.1  SARSA算法的核心原理和步骤

SARSA算法是基于时序差分(TD)学习的方法,用于估计状态-动作值函数(Q函数)并改进策略。SARSA算法的核心原理和步骤如下:

(1)初始化状态:动作值函数Q(s, a)和策略π(s, a),通常,Q函数和策略都会初始化为某些初始值。

(2)选择起始状态s,并根据策略π选择初始动作a。

(3)进入循环,执行以下步骤直到终止状态或达到最大步数:

  1. 执行动作a并观察下一个状态s'和获得的奖励r。
  2. 选择下一个动作a',通常是根据当前策略π在状态s'下选择的动作。
  3. 使用SARSA更新规则来更新Q值:

Q(s, a) <- Q(s, a) + α * [r + γ * Q(s', a') - Q(s, a)]

其中,α是学习率,γ是折扣因子,r是获得的奖励,s'是下一个状态,a'是下一个动作。

(4)更新当前状态s为下一个状态s',当前动作a为下一个动作a',重复步骤3。

(5)当终止状态达到或达到最大步数时,结束循环。

(6)根据学习到的Q函数,改进策略π,通常采用ε-贪心策略,以便在探索和利用之间取得平衡。ε-贪心策略以ε的概率选择随机动作,以1-ε的概率选择具有最高Q值的动作。

(7)重复步骤2到步骤6,直到Q函数收敛或达到一定的迭代次数。

SARSA算法的核心思想是通过不断地与环境交互,观察奖励信号并更新Q值,逐渐改进策略。它是一种在线学习方法,能够在学习的同时进行策略改进,因此适用于实时决策问题。

总之,SARSA算法是强化学习中的一种基本方法,用于解决控制问题,例如机器人导航、游戏控制和自动驾驶等领域。通过学习Q值函数,SARSA能够找到一个最优策略,以最大化累积奖励。

在下面将讲解一个简单的例子,演示使用SARSA算法来解决一个简易强化学习问题的过程。在这个例子中,我们将考虑一个智能体在迷宫中找到目标的问题。智能体可以在一个4x4的网格世界中移动,每个格子都是一个状态,智能体可以选择上、下、左、右四个动作。

实例5-2:使用SARSA算法学习一个最优策略(源码路径:daima\5\sar.py

实例文件sar.py的具体实现代码如下所示。

import numpy as np

# 定义迷宫的状态空间和动作空间
num_states = 16  # 状态数量
num_actions = 4  # 动作数量(上、下、左、右)

# 初始化状态值函数和状态-动作值函数
V = np.zeros(num_states)  # 状态值函数
Q = np.zeros((num_states, num_actions))  # 状态-动作值函数

# 设置迷宫的环境参数
gamma = 0.9  # 折扣因子
alpha = 0.1  # 学习率

# 定义ε-贪心策略
def epsilon_greedy_policy(state, epsilon):
    if np.random.rand() < epsilon:
        return np.random.choice(num_actions)  # 随机选择动作
    else:
        return np.argmax(Q[state, :])  # 选择具有最高Q值的动作

# 主循环
num_episodes = 1000  # 迭代次数
epsilon = 0.1  # ε-贪心策略中的ε

for episode in range(num_episodes):
    state = 0  # 起始状态

    while state != 15:  # 直到达到目标状态
        action = epsilon_greedy_policy(state, epsilon)  # 根据策略选择动作
        
        # 根据选择的动作更新状态
        if action == 0:  # 上
            next_state = state - 4 if state >= 4 else state  # 避免越界
        elif action == 1:  # 下
            next_state = state + 4 if state <= 11 else state  # 避免越界
        elif action == 2:  # 左
            next_state = state - 1 if state % 4 != 0 else state  # 避免越界
        elif action == 3:  # 右
            next_state = state + 1 if (state + 1) % 4 != 0 else state  # 避免越界
        
        reward = 0 if state == 14 else -1  # 设置奖励,目标状态获得奖励0,其他状态获得奖励-1

        # 使用SARSA更新规则来更新Q值
        next_action = epsilon_greedy_policy(next_state, epsilon)  # 选择下一个动作
        Q[state, action] = Q[state, action] + alpha * (reward + gamma * Q[next_state, next_action] - Q[state, action])

        state = next_state

# 输出学习到的Q值
print("学习到的Q值:")
print(Q)

# 输出最优策略
optimal_policy = np.argmax(Q, axis=1)
print("最优策略:")
print(optimal_policy.reshape(4, 4))

在上述代码中,使用SARSA算法来学习一个最优策略,使得智能体能够在迷宫中找到目标状态15。通过不断迭代和更新Q值,最终学得的最优策略会被打印出来。执行后会输出:

学习到的Q值:
[[-4.76844854 -4.29974806 -4.7126357  -4.23649292]
 [-3.85179408 -3.69747278 -4.33035675 -3.56982028]
 [-2.96947597 -2.83030074 -3.18398472 -2.99204305]
 [-2.52180616 -2.50499728 -2.51400223 -2.54132284]
 [-4.26213266 -3.62205358 -3.83822461 -3.59305329]
 [-3.6400981  -3.0269652  -3.86532257 -2.99906992]
 [-2.9900878  -2.07351811 -3.01762095 -2.34604354]
 [-1.9332492  -1.86373065 -1.88137894 -1.89921091]
 [-3.36357758 -2.89184147 -3.06576498 -2.89182258]
 [-3.26623287 -1.94377029 -2.8509975  -2.10281341]
 [-2.20776388 -1.00687126 -2.29218788 -1.76499995]
 [-1.09660746 -0.99800332 -1.21062356 -1.2113858 ]
 [-2.137907   -2.4566527  -2.21382482 -2.00671158]
 [-2.3567083  -1.65172256 -2.53248934 -1.06156418]
 [-0.84300773 -0.13426354 -0.93943256  0.        ]
 [ 0.          0.          0.          0.        ]]
最优策略:
[[3 3 1 1]
 [3 3 1 1]
 [3 1 1 1]
 [3 3 3 0]]

注意:这只是一个简化的例子,用于演示SARSA算法的应用。在实际应用中,要解决的问题可能会更复杂,状态和动作空间可能会更大,但SARSA算法的核心思想和更新规则仍然适用。

5.2.2  SARSA算法的更新规则

SARSA算法(State-Action-Reward-State-Action)的更新规则用于更新状态-动作值函数Q(s, a),以便在马尔可夫决策过程(MDP)中学习最优策略。SARSA的更新规则基于时序差分(TD)学习的思想,它描述了如何使用新的经验来逐步更新Q值。SARSA算法的更新规则如下:

对于在时间步骤t观察到的状态-动作对 (s_t, a_t) 和在时间步骤t+1观察到的状态-动作对 (s_t+1, a_t+1),以及在时间步骤t+1获得的奖励 r_t+1,使用以下公式来更新Q值:

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)]

对上述公示的具体说明如下:

  1. Q(s_t, a_t) 是在时间步骤t时状态-动作值函数的估计值,表示在状态s_t下采取动作a_t的预期累积奖励。
  2. α 是学习率,控制了每次更新的步长。较小的学习率会导致稳定的学习,但需要更多的时间来收敛,而较大的学习率可能导致不稳定的学习。
  3. r_t+1 是在时间步骤t+1时获得的奖励,表示从状态s_t到状态s_t+1采取动作a_t的立即奖励。
  4. γ 是折扣因子,表示未来奖励的重要性。它控制了对未来奖励的权重。较大的γ会强调长期奖励,较小的γ会强调短期奖励。
  5. Q(s_t+1, a_t+1) 是在时间步骤t+1时状态-动作值函数的估计值,表示在状态s_t+1下采取动作a_t+1的预期累积奖励。

SARSA算法根据当前状态-动作对 (s_t, a_t) 和下一个状态-动作对 (s_t+1, a_t+1) 来更新Q值。这意味着它是一个基于样本的算法,每次更新都依赖于在环境中观察到的实际经验。

通过反复应用SARSA的更新规则,Q值会逐渐收敛到最优值,从而允许智能体学习最优策略。这使得SARSA成为解决强化学习问题的有效方法之一。请看下面的例子,我们考虑设计一个智能体,能够在一个抽象的状态空间中学习如何选择数字,以最大化它们的总和。

实例5-3:在一个抽象状态空间中学习选择数字(源码路径:daima\5\geng.py

实例文件geng.py的具体实现代码如下所示。

import numpy as np

# 定义状态空间和动作空间
num_states = 10  # 状态数量
num_actions = 2  # 动作数量(选择数字1或选择数字2)

# 初始化状态值函数和状态-动作值函数
V = np.zeros(num_states)  # 状态值函数
Q = np.zeros((num_states, num_actions))  # 状态-动作值函数

# 设置环境参数
gamma = 0.9  # 折扣因子
alpha = 0.1  # 学习率

# 定义ε-贪心策略
def epsilon_greedy_policy(state, epsilon):
    if np.random.rand() < epsilon:
        return np.random.choice(num_actions)  # 随机选择动作
    else:
        return np.argmax(Q[state, :])  # 选择具有最高Q值的动作

# 主循环
num_episodes = 1000  # 迭代次数
epsilon = 0.1  # ε-贪心策略中的ε

for episode in range(num_episodes):
    state = np.random.randint(num_states)  # 随机选择一个初始状态

    while True:  # 连续状态空间,无终止状态
        action = epsilon_greedy_policy(state, epsilon)  # 根据策略选择动作
        if action == 0:
            next_state = state + 1  # 选择数字1,移动到下一个状态
        else:
            next_state = state + 2  # 选择数字2,移动到下下个状态
        
        if next_state >= num_states:  # 确保不会移动到状态空间之外
            next_state = num_states - 1
        
        reward = next_state  # 奖励为下一个状态的值

        # 使用SARSA更新规则来更新Q值
        next_action = epsilon_greedy_policy(next_state, epsilon)  # 选择下一个动作
        Q[state, action] = Q[state, action] + alpha * (reward + gamma * Q[next_state, next_action] - Q[state, action])

        state = next_state

        if state == num_states - 1:  # 达到最大状态时结束本次迭代
            break

# 输出学习到的Q值
print("学习到的Q值:")
print(Q)

# 输出最优策略
optimal_policy = np.argmax(Q, axis=1)
print("最优策略:")
print(optimal_policy)

在上述代码中,智能体通过选择数字1或数字2来移动,每个数字都对应一个状态。智能体的目标是选择数字以最大化它们的总和。通过添加条件 if next_state >= num_states,可以确保智能体不会移动到状态空间之外。通过使用SARSA算法,我们可以观察到Q值如何根据更新规则逐渐收敛,以及如何得到最优策略。执行后会输出:

学习到的Q值:
[[34.43028231 22.32521625]
 [42.25787707 25.47889332]
 [47.13614353 32.88775433]
 [49.81476976 42.38731994]
 [50.86117317 40.25968521]
 [50.5174039  43.95460686]
 [49.79699956 43.45282603]
 [47.77973413 42.79725199]
 [48.9841982  22.03879733]
 [49.32088977  7.69283257]]
最优策略:
[0 0 0 0 0 0 0 0 0 0]

根据上述输出结果可知,智能体在学习过程中更喜欢选择动作0(选择数字1),因为Q值在动作0上较大。最优策略显示智能体在大多数状态下都选择动作0。

注意:由于这个例子的环境和奖励设计非常简单,因此最优策略可能非常明显。在更复杂的问题中,SARSA算法将不断探索并尝试不同的策略,以找到最优策略。这个示例的目的是演示SARSA算法的更新规则,而不是复杂的问题建模。如果您有更具体或复杂的问题,需要相应调整状态空间、动作空间和奖励函数来适应问题的特性。

5.2.3  SARSA算法的收敛性与收敛条件

SARSA算法的收敛性取决于一些因素,包括算法的参数设置、环境的特性以及策略的选择。影响SARSA算法收敛性的关键因素以及一些常见的收敛条件如下:

  1. 学习率(α):学习率控制了每次Q值更新的步长。如果学习率过大,可能会导致算法不稳定,Q值不收敛。较小的学习率有助于稳定学习,但可能需要更多的时间来收敛。
  2. 折扣因子(γ):折扣因子表示未来奖励的重要性。较大的γ会强调长期奖励,较小的γ会强调短期奖励。选择合适的γ通常需要根据问题的特性进行调整。
  3. 初始Q值:初始Q值的选择也可以影响收敛性。如果初始Q值过高或过低,可能会影响学习过程。通常,Q值可以初始化为零或随机小值。
  4. 策略选择:SARSA算法通常使用ε-贪心策略来在探索和利用之间取得平衡。策略选择的方式可以影响算法的收敛性。合理的策略选择可以帮助算法在有限的迭代中达到最优策略。
  5. 状态空间和动作空间:问题的状态空间和动作空间的大小可以影响算法的收敛性。较大的状态空间和动作空间可能需要更多的迭代才能达到收敛。
  6. 随机性:如果环境具有较大的随机性,可能需要更多的迭代来收敛。一些问题可能需要更高的探索率(ε)来处理随机性。
  7. 收敛条件:通常,SARSA算法的收敛条件是当Q值函数不再发生显著变化时,算法可以被认为已经收敛。这可以通过监测Q值的变化来确定。一种常见的停止条件是当两次迭代之间的Q值变化小于某个阈值时停止。

注:SARSA算法的收敛性并不是绝对保证的,因为它受到问题的复杂性和算法参数的影响。在实践中,可以通过调整参数、增加迭代次数以及使用合适的策略来提高SARSA算法的收敛性。此外,还有一些改进的算法,如Q-learning和深度强化学习方法,可以用于处理更复杂的问题和提高收敛速度。

为了演示SARSA算法的收敛性和收敛条件,我们考虑一个简单的网格世界问题,其中智能体必须学会找到目标状态,并且智能体只有在到达目标状态时才能获得奖励。在下面的例子中,将让SARSA算法与不同的参数和条件运行,并观察它的收敛性。

实例5-4:观察SARSA算法的收敛性(源码路径:daima\5\shou.py

实例文件shou.py的具体实现代码如下所示。

import numpy as np

# 定义网格世界的参数
num_states = 16  # 状态数量
num_actions = 4  # 动作数量(上、下、左、右)
goal_state = 15  # 目标状态

# 初始化状态值函数和状态-动作值函数
V = np.zeros(num_states)  # 状态值函数
Q = np.zeros((num_states, num_actions))  # 状态-动作值函数

# 设置环境参数
gamma = 0.9  # 折扣因子
alpha = 0.1  # 学习率

# 定义ε-贪心策略
def epsilon_greedy_policy(state, epsilon):
    if np.random.rand() < epsilon:
        return np.random.choice(num_actions)  # 随机选择动作
    else:
        return np.argmax(Q[state, :])  # 选择具有最高Q值的动作

# 主循环
num_episodes = 1000  # 迭代次数
epsilon = 0.1  # ε-贪心策略中的ε

converged = False  # 是否已收敛
convergence_threshold = 0.01  # 收敛阈值

for episode in range(num_episodes):
    state = 0  # 起始状态

    while state != goal_state:  # 直到达到目标状态
        action = epsilon_greedy_policy(state, epsilon)  # 根据策略选择动作
        if action == 0:
            next_state = state - 4 if state >= 4 else state  # 向上移动
        elif action == 1:
            next_state = state + 4 if state < 12 else state  # 向下移动
        elif action == 2:
            next_state = state - 1 if state % 4 != 0 else state  # 向左移动
        else:
            next_state = state + 1 if state % 4 != 3 else state  # 向右移动
        
        reward = 0 if next_state != goal_state else 1  # 到达目标状态获得奖励1,否则奖励为0

        # 使用SARSA更新规则来更新Q值
        next_action = epsilon_greedy_policy(next_state, epsilon)  # 选择下一个动作
        Q[state, action] = Q[state, action] + alpha * (reward + gamma * Q[next_state, next_action] - Q[state, action])

        state = next_state

    # 计算状态值函数的变化
    V_new = np.max(Q, axis=1)
    delta = np.max(np.abs(V_new - V))
    V = V_new

    # 如果状态值函数的变化小于阈值,认为已经收敛
    if delta < convergence_threshold:
        converged = True
        break

if converged:
    print("SARSA算法已收敛。")
else:
    print("SARSA算法未收敛。")

# 输出学习到的Q值
print("学习到的Q值:")
print(Q)

上述代码演示了使用SARSA算法解决一个简单的网格世界问题,并观察算法的收敛性的过程。对上述代码的具体说明如下:

  1. 首先,我们定义了网格世界的参数,包括状态数量、动作数量和目标状态。
  2. 初始化了状态值函数(V)和状态-动作值函数(Q)的数组,这些数组将在算法中被更新。
  3. 设置了环境参数,包括折扣因子(gamma)和学习率(alpha)。
  4. 定义了ε-贪心策略,该策略根据ε的概率随机选择动作,或以1-ε的概率选择具有最高Q值的动作。
  5. 在主循环中,运行了多个迭代(即多个"episode"),每个"episode"代表智能体在环境中的一次尝试。
  6. 在每个"episode"中,智能体从起始状态开始,然后根据ε-贪心策略选择动作,并与环境互动。根据动作,智能体可能向上、向下、向左或向右移动。
  7. 每次与环境互动后,智能体使用SARSA更新规则来更新状态-动作值函数(Q)。这个规则基于当前状态、当前动作、奖励、下一个状态和下一个动作。
  8. 计算状态值函数(V)的变化,并检查是否满足收敛条件。如果状态值函数的变化小于预定义的收敛阈值,我们认为算法已经收敛。
  9. 最后,打印输出了学习到的Q值以及收敛的状态。如果算法在有限迭代次数内达到了收敛条件,将输出"SARSA算法已收敛",否则输出"SARSA算法未收敛"。

执行后会输出:

SARSA算法已收敛。
学习到的Q值:
[[0.00000000e+00 4.38191782e-04 2.47966835e-02 2.82287679e-01]
 [2.61896228e-02 0.00000000e+00 2.30061469e-02 4.12315376e-01]
 [5.16222372e-03 5.55781071e-01 3.34932020e-02 2.58672170e-03]
 [0.00000000e+00 0.00000000e+00 7.09085006e-02 0.00000000e+00]
 [1.11062153e-02 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [2.70916548e-03 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [2.05883575e-03 9.36199740e-03 0.00000000e+00 6.59864386e-01]
 [0.00000000e+00 8.12145084e-01 0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [1.09475523e-01 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [8.41325937e-02 9.98382691e-01 1.78119981e-03 2.42613509e-01]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]]

上面的输出表明SARSA算法已经收敛,并展示了学习到的Q值。每个Q值表示在特定状态下采取特定动作的估计价值。根据Q值,智能体可以根据ε-贪心策略来选择动作,以最大化预期累积奖励。在这个输出中,你可以看到Q值矩阵的各个元素,每个元素对应一个状态和动作的组合。算法通过与环境互动,不断地更新这些Q值,以最终学习到一个最优策略。

5.2.4  SARSA算法实例分析

请看下面的实例,这是一个基于强化学习和SARSA算法的股票买卖决策系统。在本实例中,使用强化学习方法来优化在股票环境中的买卖策略,并通过可视化来展示奖励曲线以及买入卖出点。通过不断训练,模型将尝试找到最优的策略以最大化累积奖励。

实例5-5:股票买卖决策系统(源码路径:daima\2\data.py和qiang.py

编写文件sas.py,功能是使用SARSA算法在股票环境中实现买卖策略,并通过可视化来展示奖励曲线以及买入卖出点。在本实例中使用了SARSA算法的思想,因为在 train_rl_model 函数中,它在每个时间步中选择下一个动作(next_action),并使用该动作来计算目标Q值,这是SARSA的特征。文件sas.py的主要实现代码如下所示。

plt.rcParams["axes.unicode_minus"] = False
plt.rcParams['font.sans-serif'] = ['kaiti']


class StockEnvironment:
    def __init__(self, data):
        self.data = data
        self.current_step = 0
        self.initial_balance = 10000
        self.balance = self.initial_balance
        self.stock_holding = 0
        self.max_steps = len(data) - 1
        self.buy_points = []
        self.sell_points = []

    def reset(self):
        self.current_step = 0
        self.balance = self.initial_balance
        self.stock_holding = 0
        self.buy_points = []
        self.sell_points = []
        return self._get_state()

    def _get_state(self):
        return np.array([
            self.data['close'][self.current_step],
            self.balance,
            self.stock_holding
        ])

    def step(self, action):
        if action == 0:
            if self.balance > self.data['close'][self.current_step]:
                self.stock_holding += 1
                self.balance -= self.data['close'][self.current_step]
                self.buy_points.append(self.current_step)
        elif action == 1:
            if self.stock_holding > 0:
                self.stock_holding -= 1
                self.balance += self.data['close'][self.current_step]
                self.sell_points.append(self.current_step)

        self.current_step += 1

        if self.current_step == self.max_steps:
            done = True
            reward = self.balance + self.stock_holding * self.data['close'][self.current_step]
        else:
            done = False
            reward = 0

        return self._get_state(), reward, done


class QNetwork(nn.Module):
    def __init__(self, input_size, output_size):
        super(QNetwork, self).__init__()
        self.fc1 = nn.Linear(input_size, 64)
        self.fc2 = nn.Linear(64, output_size)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x


# 修改贝尔曼方程近似以支持SARSA算法
def bellman_approximation(current_state, next_state, reward, gamma, model, next_action):
    current_state_value = model(torch.tensor(current_state, dtype=torch.float32).unsqueeze(0)).gather(1, torch.tensor(
        [[next_action]]))

    epsilon = 0.1
    if np.random.rand() < epsilon:
        next_action = np.random.randint(output_size)
    else:
        next_action = model(torch.tensor(next_state, dtype=torch.float32).unsqueeze(0)).argmax().item()

    next_state_value = model(torch.tensor(next_state, dtype=torch.float32).unsqueeze(0)).gather(1, torch.tensor(
        [[next_action]]))

    target = reward + gamma * next_state_value
    return target - current_state_value


def train_rl_model(data, num_episodes, batch_size, model):
    input_size = 3
    output_size = 2
    gamma = 0.99
    learning_rate = 0.001

    model = QNetwork(input_size, output_size)
    target_model = QNetwork(input_size, output_size)
    target_model.load_state_dict(model.state_dict())
    target_model.eval()

    optimizer = optim.Adam(model.parameters(), lr=learning_rate)
    criterion = nn.MSELoss()

    episode_rewards = []

    for episode in range(num_episodes):
        env = StockEnvironment(data)
        state = env.reset()
        total_reward = 0

        epsilon = 0.1

        while True:
            with torch.no_grad():
                q_values = model(torch.tensor(state, dtype=torch.float32).unsqueeze(0))

            if np.random.rand() < epsilon:
                action = np.random.randint(output_size)
            else:
                action = q_values.argmax().item()

            next_state, reward, done = env.step(action)
            next_action = torch.tensor([[action]], dtype=torch.long)

            target = bellman_approximation(
                torch.tensor(state, dtype=torch.float32),
                torch.tensor(next_state, dtype=torch.float32),
                reward, gamma, model, next_action
            )

            output = model(torch.tensor(state, dtype=torch.float32).unsqueeze(0))

            loss = criterion(output.gather(1, torch.tensor([[action]])), target)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            total_reward += reward
            state = next_state

            if done:
                episode_rewards.append(total_reward)
                break

        if episode % 10 == 0:
            target_model.load_state_dict(model.state_dict())

        if episode % 50 == 0:
            print(f"Episode {episode}/{num_episodes}, Total Reward: {total_reward}")

    return model, episode_rewards


if __name__ == "__main__":
    data = pd.read_csv('stock_data.csv')
    input_size = 3
    output_size = 2
    model = QNetwork(input_size, output_size)

    num_episodes = 100
    batch_size = 32
    trained_model, episode_rewards = train_rl_model(data, num_episodes, batch_size, model)

    plt.figure(figsize=(12, 6))
    plt.title('强化学习奖励和买卖点')
    plt.plot(episode_rewards, label='Total Reward', color='blue')
    plt.xlabel('Episode')
    plt.ylabel('Total Reward')
    plt.grid(True)

    buy_sell_points = []
    env = StockEnvironment(data)
    state = env.reset()
    for i in range(len(episode_rewards)):
        with torch.no_grad():
            q_values = model(torch.tensor(state, dtype=torch.float32).unsqueeze(0))
            action = q_values.argmax().item()
        if action == 0:
            buy_sell_points.append((i, episode_rewards[i], 'Buy'))
        elif action == 1:
            buy_sell_points.append((i, episode_rewards[i], 'Sell'))

        next_state, _, _ = env.step(action)
        state = next_state

    for point in buy_sell_points:
        episode, reward, action = point
        plt.axvline(x=episode, color='red', linestyle='--', label=f'{action} Point')

    plt.legend()
    plt.show()

上述代码的功能是使用强化学习方法来训练一个智能体,在股票市场中自动执行买入和卖出操作,以最大化投资组合的价值,并通过可视化展示强化学习的表现。函数bellman_approximation用于计算贝尔曼方程的估值,从而实现SARSA算法,它根据当前状态、下一个状态、奖励、模型、下一个动作等信息计算目标值。执行效果如图5-8所示。

图5-8  执行效果

未完待续

  • 15
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Q-learning和SARSA都属于时序差分强化学习方法,而不是蒙特卡洛强化学习方法。 时序差分强化学习是一种结合了动态规划和蒙特卡洛方法的强化学习方法。它通过使用经验数据进行增量式的更新,同时利用了当前和未来的估计值来逼近最优值函数。 具体来说,Q-learning和SARSA都是基于Q值函数的时序差分强化学习算法。 1. Q-learning:Q-learning是一种基于动态规划的无模型强化学习算法。它使用了时序差分(TD)方法,通过不断迭代更新Q值函数的估计值,使其逼近最优的Q值。Q-learning算法通过将当前状态和动作的估计值与下一个状态和动作的最大估计值相结合,来更新Q值函数的估计值。 2. SARSASARSA是一种基于时序差分的强化学习算法,也是一种模型-free的强化学习算法SARSA算法使用了时序差分的方法,通过不断迭代更新Q值函数的估计值。与Q-learning不同的是,SARSA算法采用了一个策略(Policy)来决定下一个动作,并在更新Q值时使用下一个动作的估计值。 时序差分强化学习方法与蒙特卡洛强化学习方法相比,具有更高的效率和更好的适应性。它可以在每个时间步骤中进行更新,不需要等到任务结束后才进行更新,从而更快地收敛到最优策略。而蒙特卡洛强化学习方法则需要等到任务结束后才能获取完整的回报信息,进行全局更新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值