用神经网络自动玩游戏

用神经网络玩游戏
CartPole是OpenAI gym中的一个游戏测试,车上顶着一个自由摆动的杆子,实现杆子的平衡,杆子每次倒向一端车就开始移动让杆子保持动态直立的状态.

游戏地址:https://gymnasium.farama.org/env ... _control/cart_pole/

一、搭建游戏运行环境

bash 复制代码
pip install swig
pip install gymnasium[box2d]

CartPole 环境内置在 gym 中,直接安装 gym 即可。其环境 id 是CartPole-v0 。Gym是一个研究和开发强化学习相关算法的仿真平台。简单来说OpenAI Gym提供了许多问题和环境(或游戏)的接口,而用户无需过多了解游戏的内部实现,通过简单地调用就可以用来测试和仿真。

bash 复制代码
pip install gym

启动游戏完整代码:

python 复制代码
import gym

# 创建 CartPole 环境
env = gym.make('CartPole-v1', render_mode="human")  # 使用新版本时,需要指定 render_mode

# 重置环境,准备开始游戏
observation, info = env.reset()

for _ in range(1000):
    # 随机选择一个动作(0或1)
    action = env.action_space.sample()

    # 应用动作到环境中,返回新的状态、奖励、完成标志和其他信息
    observation, reward, done, truncated, info = env.step(action)

    # 如果游戏结束或被截断,重置环境
    if done or truncated:
        observation, info = env.reset()

# 关闭游戏
env.close()

可以看到游戏在自动运行。

二、手动控制
增加键盘操作:

python 复制代码
# 获取键盘按键状态
keys = pygame.key.get_pressed()

# 默认动作为随机生成 0 或 1,除非检测到按键输入
if not keys[K_LEFT] and not keys[K_RIGHT]:
    action = random.choice([0, 1])  # 随机选择 0 或 1

# 根据按键改变动作
if keys[K_LEFT]:
    print("Left arrow pressed")
    action = 0  # 向左移动
elif keys[K_RIGHT]:
    print("Right arrow pressed")
    action = 1  # 向右移动

完整代码如下:

python 复制代码
import gym
import pygame
from pygame.locals import K_LEFT, K_RIGHT, QUIT
import time
import random  # 用于生成随机数

# 初始化 pygame
pygame.init()

# 设置帧率
FPS = 60
clock = pygame.time.Clock()

# 创建 CartPole 环境,使用 Gym 自带的渲染模式
env = gym.make('CartPole-v1', render_mode="human")

# 重置环境,准备开始游戏
observation, info = env.reset()

# 初始化游戏的运行标志
running = True

# 操作次数
action_count = 0

# 记录游戏开始的时间
start_time = time.time()

# 游戏循环
while running:
    # 处理事件队列,检测关闭窗口操作
    for event in pygame.event.get():
        if event.type == QUIT:  # 退出事件
            running = False
    time.sleep(0.3)

    # 获取键盘按键状态
    keys = pygame.key.get_pressed()

    # 默认动作为随机生成 0 或 1,除非检测到按键输入
    if not keys[K_LEFT] and not keys[K_RIGHT]:
        action = random.choice([0, 1])  # 随机选择 0 或 1

    # 根据按键改变动作
    if keys[K_LEFT]:
        print("Left arrow pressed")
        action = 0  # 向左移动
    elif keys[K_RIGHT]:
        print("Right arrow pressed")
        action = 1  # 向右移动

    # 执行动作并更新环境状态
    observation, reward, done, truncated, info = env.step(action)

    # 每执行一次动作,增加操作次数
    action_count += 1

    # 渲染环境,减少渲染频率(每隔 10 帧渲染一次)
    if action_count % 10 == 0:
        env.render()

    # 检查游戏是否结束
    if done or truncated:
        # 记录游戏结束的时间
        end_time = time.time()

        # 计算游戏持续的时间(秒)
        elapsed_time = end_time - start_time

        # 打印游戏信息
        print(f"游戏结束!总共操作了 {action_count} 次,持续时间为 {elapsed_time:.2f} 秒")

        # 重置环境
        observation, info = env.reset()

        # 重置计数器和时间
        action_count = 0
        start_time = time.time()

    # 控制帧率,确保游戏速度合适
    clock.tick(FPS)  # 设置帧率为 60 帧/秒

# 关闭游戏环境和 pygame
env.close()
pygame.quit()

最好成绩成功控制了57次。

三、用电脑控制

python 复制代码
#电脑自嗨
if observation[2] <= 0:
    action = 0
else:
    action = 1

电脑居然控制了59步。

四、用神经网络控制

1.训练神经网络

bash 复制代码
pip install torch
python 复制代码
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import random
from collections import deque

# 设置设备(如果有GPU则使用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 创建 CartPole 环境
env = gym.make('CartPole-v1')

# 超参数
GAMMA = 0.99  # 折扣因子
EPSILON_START = 1.0  # 初始探索率
EPSILON_END = 0.01  # 最低探索率
EPSILON_DECAY = 0.995  # 探索率衰减
LEARNING_RATE = 0.001  # 学习率
MEMORY_SIZE = 10000  # 经验回放的容量
BATCH_SIZE = 64  # 批量大小
TARGET_UPDATE = 10  # 每隔多少步更新目标网络
TRAIN_TARGET_REWARD = 5000  # 训练停止目标:游戏持续达到 5000 步

# DQN 网络结构
class DQN(nn.Module):
    def __init__(self, state_size, action_size):
        super(DQN, self).__init__()
        self.fc1 = nn.Linear(state_size, 24)
        self.fc2 = nn.Linear(24, 24)
        self.fc3 = nn.Linear(24, action_size)

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

# 经验回放池
class ReplayMemory:
    def __init__(self, capacity):
        self.memory = deque(maxlen=capacity)

    def push(self, experience):
        self.memory.append(experience)

    def sample(self, batch_size):
        return random.sample(self.memory, batch_size)

    def __len__(self):
        return len(self.memory)

# 选择动作的epsilon-greedy策略
def select_action(state, policy_net, epsilon, n_actions):
    if random.random() < epsilon:
        return random.randrange(n_actions)  # 随机探索
    else:
        with torch.no_grad():
            state = torch.tensor(state, dtype=torch.float32).unsqueeze(0).to(device)
            return policy_net(state).argmax(dim=1).item()  # 利用网络选择最优动作

# 更新目标网络
def update_target_network(policy_net, target_net):
    target_net.load_state_dict(policy_net.state_dict())

# 训练 DQN 网络
def optimize_model(policy_net, target_net, memory, optimizer):
    if len(memory) < BATCH_SIZE:
        return
   
    # 从经验回放池中采样
    experiences = memory.sample(BATCH_SIZE)
   
    # 将经验解包为不同部分
    states, actions, rewards, next_states, dones = zip(*experiences)
   
    states = torch.tensor(states, dtype=torch.float32).to(device)
    actions = torch.tensor(actions, dtype=torch.int64).unsqueeze(1).to(device)
    rewards = torch.tensor(rewards, dtype=torch.float32).unsqueeze(1).to(device)
    next_states = torch.tensor(next_states, dtype=torch.float32).to(device)
    dones = torch.tensor(dones, dtype=torch.float32).unsqueeze(1).to(device)
   
    # 当前 Q 值
    q_values = policy_net(states).gather(1, actions)
   
    # 下一个状态的最大 Q 值(目标网络)
    with torch.no_grad():
        max_next_q_values = target_net(next_states).max(1)[0].unsqueeze(1)
        target_q_values = rewards + (GAMMA * max_next_q_values * (1 - dones))

    # 计算损失
    loss = nn.MSELoss()(q_values, target_q_values)
   
    # 反向传播优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

# 初始化 DQN 网络和目标网络
n_actions = env.action_space.n
state_size = env.observation_space.shape[0]

policy_net = DQN(state_size, n_actions).to(device)
target_net = DQN(state_size, n_actions).to(device)
update_target_network(policy_net, target_net)

# 优化器
optimizer = optim.Adam(policy_net.parameters(), lr=LEARNING_RATE)

# 经验回放
memory = ReplayMemory(MEMORY_SIZE)

# 训练主循环
epsilon = EPSILON_START
num_episodes = 1000

for episode in range(num_episodes):
    state, _ = env.reset()
    done = False
    total_steps = 0
    total_reward = 0

    while not done:
        # 选择动作
        action = select_action(state, policy_net, epsilon, n_actions)

        # 执行动作
        next_state, reward, done, truncated, _ = env.step(action)
        total_steps += 1
        total_reward += reward

        # 如果游戏结束,则给负奖励
        reward = reward if not done else -10

        # 将经验存入回放池
        memory.push((state, action, reward, next_state, done))

        # 更新状态
        state = next_state

        # 训练模型
        optimize_model(policy_net, target_net, memory, optimizer)

        # 停止训练条件:游戏累计达到5000步,保存模型
        if total_steps >= TRAIN_TARGET_REWARD:
            print(f"Training completed after {episode+1} episodes, reaching {total_steps} steps.")
            torch.save(policy_net.state_dict(), 'dqn_cartpole.pth')
            break

    # 每隔一定步数更新目标网络
    if episode % TARGET_UPDATE == 0:
        update_target_network(policy_net, target_net)

    # epsilon衰减
    epsilon = max(EPSILON_END, EPSILON_DECAY * epsilon)

    print(f"Episode {episode + 1}/{num_episodes},total_steps:{total_steps}, Total Reward: {total_reward}")

    # 检查是否已经达到目标
    if total_steps >= TRAIN_TARGET_REWARD:
        break

env.close()

保存模型的代码:

python 复制代码
# 训练结束后保存模型
if total_steps >= TRAIN_TARGET_REWARD:
    print(f"Training completed after {episode+1} episodes, reaching {total_steps} steps.")
    torch.save(policy_net.state_dict(), 'dqn_cartpole.pth')
    break

模型保存成功,大小6kb

2.使用神经网络控制游戏:
调用神经网络决策关键代码:

python 复制代码
    state_tensor = torch.tensor(observation, dtype=torch.float32).unsqueeze(0).to(device)
    action = policy_net(state_tensor).argmax(dim=1).item()

使用模型并调用神经网络控制完整代码如下:

python 复制代码
import gym
import pygame
import torch
import torch.nn as nn
from pygame.locals import K_LEFT, K_RIGHT, QUIT
import time
import random  # 用于生成随机数

# 设置设备(如果有GPU则使用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 初始化 pygame
pygame.init()

# 设置帧率
FPS = 60
clock = pygame.time.Clock()

# 创建 CartPole 环境,使用 Gym 自带的渲染模式
env = gym.make('CartPole-v1', render_mode="human")

# 重置环境,准备开始游戏
observation, info = env.reset()

# 初始化游戏的运行标志
running = True

# 操作次数
action_count = 0

# 记录游戏开始的时间
start_time = time.time()

# DQN 网络结构
class DQN(nn.Module):
    def __init__(self, state_size, action_size):
        super(DQN, self).__init__()
        self.fc1 = nn.Linear(state_size, 24)
        self.fc2 = nn.Linear(24, 24)
        self.fc3 = nn.Linear(24, action_size)

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

# 初始化 DQN 网络和目标网络
n_actions = env.action_space.n
state_size = env.observation_space.shape[0]

# 加载模型并使用神经网络控制游戏
policy_net = DQN(state_size, n_actions).to(device)

# 加载训练好的模型权重
MODEL_PATH = 'dqn_cartpole.pth'
policy_net.load_state_dict(torch.load(MODEL_PATH))

# 设置为评估模式
policy_net.eval()

# 游戏循环
while running:
    # 处理事件队列,检测关闭窗口操作
    for event in pygame.event.get():
        if event.type == QUIT:  # 退出事件
            running = False
    time.sleep(0.3)

    # 获取键盘按键状态
    keys = pygame.key.get_pressed()

    # 默认动作为随机生成 0 或 1,除非检测到按键输入
    if not keys[K_LEFT] and not keys[K_RIGHT]:
        action = random.choice([0, 1])  # 随机选择 0 或 1

    # 根据按键改变动作
    if keys[K_LEFT]:
        print("Left arrow pressed")
        action = 0  # 向左移动
    elif keys[K_RIGHT]:
        print("Right arrow pressed")
        action = 1  # 向右移动
        
    state_tensor = torch.tensor(observation, dtype=torch.float32).unsqueeze(0).to(device)
    action = policy_net(state_tensor).argmax(dim=1).item()

    # 执行动作并更新环境状态
    observation, reward, done, truncated, info = env.step(action)

    # 每执行一次动作,增加操作次数
    action_count += 1

    # 渲染环境,减少渲染频率(每隔 10 帧渲染一次)
    if action_count % 10 == 0:
        env.render()

    # 检查游戏是否结束
    if done or truncated:
        # 记录游戏结束的时间
        end_time = time.time()

        # 计算游戏持续的时间(秒)
        elapsed_time = end_time - start_time

        # 打印游戏信息
        print(f"游戏结束!总共操作了 {action_count} 次,持续时间为 {elapsed_time:.2f} 秒")

        # 重置环境
        observation, info = env.reset()

        # 重置计数器和时间
        action_count = 0
        start_time = time.time()

    # 控制帧率,确保游戏速度合适
    clock.tick(FPS)  # 设置帧率为 60 帧/秒

# 关闭游戏环境和 pygame
env.close()
pygame.quit()

每次都能顺利通关

更详细:

用神经网络自动玩游戏

https://www.jinshuangshi.com/forum.php?mod=viewthread\&tid=353

(出处: 金双石科技)

相关推荐
这个男人是小帅5 小时前
【图神经网络】 AM-GCN论文精讲(全网最细致篇)
人工智能·pytorch·深度学习·神经网络·分类
坠金12 小时前
神经网络的常用layer
人工智能·深度学习·神经网络
T0uken16 小时前
【机器学习】Softmax 函数
神经网络·机器学习·分类
棉猴1 天前
《Python游戏编程入门》注-第4章1
python·pygame·游戏编程·键盘按键监听·鼠标按键监听
sp_fyf_20241 天前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-26
人工智能·深度学习·神经网络·算法·机器学习·语言模型·自然语言处理
小黄编程快乐屋1 天前
使用Python来下一场雪
开发语言·python·pygame
人工智能老林2 天前
通俗直观介绍ChatGPT背后的大语言模型理论知识
人工智能·神经网络·机器学习·语言模型·自然语言处理·chatgpt·agi
一裤兜代码2 天前
sac网络搭建(遇到的各种坑)
python·神经网络
魏大帅。2 天前
机器学习与神经网络:发展历程及其对社会经济的深远影响
人工智能·神经网络·机器学习
jamison_12 天前
机器学习与神经网络的发展前景及其与传统物理学的关系
人工智能·深度学习·神经网络·1024程序员节