为什么现在的强化学习算法不使用纯蒙特卡洛的方法? —— 使用蒙特卡洛法求解强化学习算法中的q值/q函数值

自己用AI大模型生成了一个使用蒙特卡洛法求解强化学习算法中的q值/q函数值的代码,发现这个蒙特卡洛法求解函数拟合的q值的强化学习算法性能简直是太low了。


通过本文中的代码可以知道,虽然都是使用函数拟合的方法来表示q值(使用pytorch中的神经网络模型mlp),但是q-learning算法所得到的算法模型性能更优,训练速度更快(本文没有给出q-learning算法的代码实现,该代码实现比较常见,这里就不再给出),而使用函数拟合表示q值并使用蒙特卡洛方法进行模型训练的方式训练,所得到的算法模型性能十分的有限,并且训练时间也更长,训练稳定性也更差,收敛性也更差。


而且更为需要注意的是,使用函数拟合q值并使用蒙特卡洛法进行训练的方式中,如果训练的时候使用多个episodes的数据时甚至可能使算法的性能更差,不过这样也有可能使训练的稳定性更强,但是算法的性能就更可能变差。该种方法下,算法模型的最终性能可能远远低于q-learning方法。


函数拟合q值并使用蒙特卡洛法进行训练的方式,同时训练的episodes(回合数量)越多则训练过程更稳定,但是其算法模型的性能(天花板)可能越差。


下面代码中使用的仿真环境为cartpole小车。





代码:(AI大模型生成)


import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from collections import deque
import random

# ---------------------------
# Q 网络(PyTorch)
# ---------------------------
class QNet(nn.Module):
    def __init__(self, state_dim, action_dim, hidden_dim=128):
        super().__init__()
        self.fc = nn.Sequential(
            nn.Linear(state_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, action_dim)
        )

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

# ---------------------------
# 蒙特卡洛 Q-Learning
# ---------------------------
class MonteCarloQLearning:
    def __init__(self, state_dim, action_dim, gamma=0.99, lr=1e-3):
        self.gamma = gamma
        self.action_dim = action_dim
        self.q_net = QNet(state_dim, action_dim)
        self.optimizer = optim.Adam(self.q_net.parameters(), lr=lr)
        self.loss_fn = nn.MSELoss()

    def act(self, state, eps=0.1):
        # epsilon-greedy
        if random.random() < eps:
            return random.randint(0, self.action_dim - 1)
        with torch.no_grad():
            s = torch.FloatTensor(state)
            q = self.q_net(s)
        return q.argmax().item()

    def update(self, trajectory_s):
        L = 0
        self.optimizer.zero_grad()

        for trajectory in trajectory_s:
            # trajectory: [(s, a, r), ...]
            states, actions, rewards = zip(*trajectory)
            states = torch.FloatTensor(states)
            actions = torch.LongTensor(actions).unsqueeze(1)

            # 计算折扣回报 G(蒙特卡洛核心)
            G = 0
            returns = []
            for r in reversed(rewards):
                G = r + self.gamma * G
                returns.append(G)
            returns = torch.FloatTensor(list(reversed(returns))).unsqueeze(1)

            # 拟合 Q(s,a) = G
            q = self.q_net(states).gather(1, actions)
            loss = self.loss_fn(q, returns)
            L += loss.item()

            loss.backward()
        self.optimizer.step()

        return L


# ---------------------------
# 主训练
# ---------------------------
batch_episodes = 1000
def train_mc_cartpole():
    all_time = 0
    ex_episode = 0

    env = gym.make("CartPole-v1")
    s_dim = env.observation_space.shape[0]
    a_dim = env.action_space.n

    agent = MonteCarloQLearning(s_dim, a_dim)
    max_episodes = 1000000
    eps = 1.0
    eps_min = 0.01
    eps_decay = 0.995

    traj_s = []
    for epi in range(max_episodes):
        s = env.reset()
        if isinstance(s, tuple):
            s = s[0]
        traj = []
        total_reward = 0
        done = False

        while not done:
            a = agent.act(s, eps)
            ns, r, terminated, truncated, _ = env.step(a)
            done = terminated or truncated
            traj.append((s, a, r))
            s = ns
            total_reward += r
        traj_s.append(traj)

        if len(traj_s)>=batch_episodes:
            # 回合结束才更新(蒙特卡洛特点)
            loss = agent.update(traj_s)
            traj_s.clear()

            # 衰减探索率
            if eps > eps_min:
                eps *= eps_decay
            print(f"Episode {epi:3d} | Reward: {total_reward:4.0f} | Loss: {loss/batch_episodes:.3f} | eps: {eps:.3f}")
        # else:
        #     print(f"Episode {epi:3d} | Reward: {total_reward:4.0f}")

        # 认为连续高分即解决
        if total_reward >= 490:
            if epi == ex_episode+1:
                all_time += 1
            else:
                all_time = 1
            ex_episode = epi
            if all_time == 10:
                print("CartPole 已通过蒙特卡洛强化学习解决!")
                break

    env.close()

if __name__ == "__main__":
    train_mc_cartpole()

image


image


image


image


image











posted on 2026-08-03 22:11  Angry_Panda  阅读(2)  评论(0)    收藏  举报

导航