You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于PyTorch的黑箱二维函数寻优深度强化学习实现问询

无Gym依赖的Q-Learning智能体实现(PyTorch)

完全可以用PyTorch或TensorFlow实现这个问题,不需要依赖Gym/Gymnasium类库——这个环境逻辑简单,我们可以手动实现状态转换、奖励计算的核心逻辑,直接训练Q网络智能体。

原代码的问题修正

你提供的ChatGPT生成代码存在几个影响训练效果的问题,修正点如下:

  • 学习率设置过高(原代码0.9),Adam优化器适合用1e-3量级的学习率
  • 缺少ε-greedy探索机制,智能体初期需要随机探索,避免陷入局部最优
  • 未对状态(x,y)做归一化,[-100,100]的数值范围会增加神经网络的训练难度
  • 终止状态的目标Q值计算错误:找到最大值后没有后续动作,目标Q值应直接等于当前奖励,无需加上折扣后的未来Q值
  • 多余的评估模式切换,无需在找到最大值时调用eval()

修正后的完整代码

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import random

# 设备配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# Q网络定义:输入坐标(x,y),输出4个动作的Q值
class QNetwork(nn.Module):
    def __init__(self):
        super(QNetwork, self).__init__()
        self.fc1 = nn.Linear(2, 128)
        self.fc2 = nn.Linear(128, 64)
        self.fc3 = nn.Linear(64, 4)

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

# Q学习智能体
class Agent:
    def __init__(self):
        self.q_network = QNetwork().to(device)
        self.optimizer = optim.Adam(self.q_network.parameters(), lr=1e-3)  # 修正学习率
        self.gamma = 0.95  # 折扣因子
        self.epsilon = 0.9  # 初始探索率
        self.epsilon_min = 0.01  # 最小探索率
        self.epsilon_decay = 0.995  # 探索率衰减系数

    def select_action(self, state):
        # ε-greedy策略选择动作
        if random.random() < self.epsilon:
            # 随机探索:选0-3的随机动作
            return random.randint(0, 3)
        else:
            # 利用当前最优动作
            with torch.no_grad():
                q_values = self.q_network(state)
            return torch.argmax(q_values).item()

    def update_epsilon(self):
        # 衰减探索率
        if self.epsilon > self.epsilon_min:
            self.epsilon *= self.epsilon_decay

# 黑箱函数:模拟未知地形,这里用示例函数,实际可替换为任意黑箱逻辑
def calculate_function_value(x, y):
    # 示例函数最大值在x=-1, y=-1处,z=4,对应MAX_VALUE设为4
    return 2 - x**2 - y**2 - 2*y - 2*x

# 训练参数设置
agent = Agent()
num_episodes = 1000
MAX_VALUE = 4  # 已知的函数最大值
x_range = (-100, 100)
y_range = (-100, 100)

# 状态归一化函数:把[-100,100]映射到[-1,1]
def normalize_state(x, y):
    norm_x = (x - x_range[0]) / (x_range[1] - x_range[0]) * 2 - 1
    norm_y = (y - y_range[0]) / (y_range[1] - y_range[0]) * 2 - 1
    return torch.tensor([norm_x, norm_y], dtype=torch.float32).to(device)

# 开始训练
for episode in range(num_episodes):
    # 随机初始化起始坐标
    x, y = random.randint(*x_range), random.randint(*y_range)
    state = normalize_state(x, y)
    total_reward = 0
    done = False

    while not done:
        # 选择动作
        action = agent.select_action(state)
        # 执行动作,更新坐标
        if action == 0:  # 左移
            x -= 1
            x = max(x, x_range[0])
        elif action == 1:  # 右移
            x += 1
            x = min(x, x_range[1])
        elif action == 2:  # 下移
            y -= 1
            y = max(y, y_range[0])
        elif action == 3:  # 上移
            y += 1
            y = min(y, y_range[1])
        
        # 计算新状态和奖励
        new_state = normalize_state(x, y)
        z = calculate_function_value(x, y)
        
        reward = -1
        if abs(z - MAX_VALUE) < 1e-6:  # 浮点误差容忍
            reward = 100
            done = True
        
        total_reward += reward

        # 计算目标Q值
        with torch.no_grad():
            if done:
                target_q = torch.tensor(reward, dtype=torch.float32).to(device)
            else:
                max_future_q = torch.max(agent.q_network(new_state))
                target_q = reward + agent.gamma * max_future_q
        
        # 计算当前Q值和损失
        current_q = agent.q_network(state)[action]
        loss = F.mse_loss(current_q, target_q)

        # 优化网络
        agent.optimizer.zero_grad()
        loss.backward()
        agent.optimizer.step()

        # 更新状态
        state = new_state

        # 衰减探索率
        agent.update_epsilon()

    print(f"第 {episode+1} 轮训练,总奖励: {total_reward},当前探索率: {agent.epsilon:.3f}")

# 测试智能体:从随机位置出发,验证是否能快速找到最大值
print("\n=== 测试智能体 ===")
x_test, y_test = random.randint(*x_range), random.randint(*y_range)
print(f"起始位置: ({x_test}, {y_test})")
state_test = normalize_state(x_test, y_test)
steps = 0
while True:
    action = agent.select_action(state_test)
    if action == 0:
        x_test -= 1
    elif action == 1:
        x_test += 1
    elif action == 2:
        y_test -= 1
    elif action == 3:
        y_test += 1
    steps += 1
    z_test = calculate_function_value(x_test, y_test)
    if abs(z_test - MAX_VALUE) < 1e-6:
        print(f"找到最大值!位置: ({x_test}, {y_test}),步数: {steps}")
        break
    state_test = normalize_state(x_test, y_test)

关键说明

  1. 状态归一化:将[-100,100]的坐标映射到[-1,1],让神经网络更容易学习到状态和动作的关联
  2. ε-greedy探索:初期高探索率让智能体遍历更多状态,后期逐步降低探索率,转为利用已学习的最优策略
  3. 终止状态处理:当找到最大值时,目标Q值直接等于奖励,因为没有后续动作的收益
  4. 黑箱函数替换:只需修改calculate_function_value函数,即可适配任意未知黑箱函数,无需改动其他逻辑

内容的提问来源于stack exchange,提问作者Bubble

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 16:02:10