用神经网络自动玩游戏

用神经网络玩游戏
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

(出处: 金双石科技)

相关推荐
秀儿还能再秀9 小时前
神经网络(系统性学习三):多层感知机(MLP)
神经网络·学习笔记·mlp·多层感知机
老艾的AI世界10 小时前
AI翻唱神器,一键用你喜欢的歌手翻唱他人的曲目(附下载链接)
人工智能·深度学习·神经网络·机器学习·ai·ai翻唱·ai唱歌·ai歌曲
sp_fyf_202414 小时前
【大语言模型】ACL2024论文-19 SportsMetrics: 融合文本和数值数据以理解大型语言模型中的信息融合
人工智能·深度学习·神经网络·机器学习·语言模型·自然语言处理
CoderIsArt14 小时前
基于 BP 神经网络整定的 PID 控制
人工智能·深度学习·神经网络
EterNity_TiMe_14 小时前
【论文复现】神经网络的公式推导与代码实现
人工智能·python·深度学习·神经网络·数据分析·特征分析
sp_fyf_202416 小时前
【大语言模型】ACL2024论文-18 MINPROMPT:基于图的最小提示数据增强用于少样本问答
人工智能·深度学习·神经网络·目标检测·机器学习·语言模型·自然语言处理
Mr.谢尔比17 小时前
李宏毅机器学习课程知识点摘要(1-5集)
人工智能·pytorch·深度学习·神经网络·算法·机器学习·计算机视觉
曼城周杰伦19 小时前
自然语言处理:第六十二章 KAG 超越GraphRAG的图谱框架
人工智能·pytorch·神经网络·自然语言处理·chatgpt·nlp·gpt-3
南门听露21 小时前
适用于资源受限IoT系统的非对称语义图像压缩技术
深度学习·神经网络·物联网
无脑敲代码,bug漫天飞1 天前
神经网络的初始化
人工智能·深度学习·神经网络