案例:从CartPole-v1迁移到MountainCar-v0
- 在源环境(CartPole-v1)中训练模型
首先,我们使用DQN算法在CartPole-v1环境中训练一个强化学习模型。以下是代码示例:
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import random
from collections import deque# 定义 Q 网络
class QNetwork(nn.Module):def __init__(self, state_dim, action_dim):super(QNetwork, self).__init__()self.fc1 = nn.Linear(state_dim, 128)self.fc2 = nn.Linear(128, 128)self.fc3 = nn.Linear(128, action_dim)def forward(self, x):x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))return self.fc3(x)# Replay buffer,用于存储经验
class ReplayBuffer:def __init__(self, capacity):self.buffer = deque(maxlen=capacity)def add(self, transition):self.buffer.append(transition)def sample(self, batch_size):transitions = random.sample(self.buffer, batch_size)states, actions, rewards, next_states, dones = zip(*transitions)states = np.stack(states)next_states = np.stack(next_states)actions = np.array(actions, dtype=np.int64)rewards = np.array(rewards, dtype=np.float32)dones = np.array(dones, dtype=np.float32)return states, actions, rewards, next_states, donesdef size(self):return len(self.buffer)# 选择动作
def select_action(state, policy_net, epsilon, action_dim):if random.random() < epsilon:return random.choice(np.arange(action_dim))else:with torch.no_grad():state = torch.FloatTensor(state).unsqueeze(0)q_values = policy_net(state)return q_values.argmax().item()# Q-learning 更新
def update_model(policy_net, target_net, optimizer, replay_buffer, batch_size, gamma):if replay_buffer.size() < batch_size:returnstates, actions, rewards, next_states, dones = replay_buffer.sample(batch_size)states = torch.FloatTensor(states)actions = torch.LongTensor(actions)rewards = torch.FloatTensor(rewards)next_states = torch.FloatTensor(next_states)dones = torch.FloatTensor(dones)q_values = policy_net(states).gather(1, actions.unsqueeze(1)).squeeze(1)next_q_values = target_net(next_states).max(1)[0]target_q_values = rewards + gamma * next_q_values * (1 - dones)loss = (q_values - target_q_values.detach()).pow(2).mean()optimizer.zero_grad()loss.backward()optimizer.step()# 训练模型
def train_dqn(env_name, num_episodes=500, gamma=0.99, epsilon_start=1.0, epsilon_end=0.01, epsilon_decay=0.995, batch_size=64):env = gym.make(env_name)state_dim = env.observation_space.shape[0]action_dim = env.action_space.npolicy_net = QNetwork(state_dim, action_dim)target_net = QNetwork(state_dim, action_dim)target_net.load_state_dict(policy_net.state_dict())target_net.eval()optimizer = optim.Adam(policy_net.parameters())replay_buffer = ReplayBuffer(10000)epsilon = epsilon_startfor episode in range(num_episodes):state, _ = env.reset()total_reward = 0while True:action = select_action(state, policy_net, epsilon, action_dim)next_state, reward, done, _, __ = env.step(action)replay_buffer.add((state, action, reward, next_state, done))state = next_statetotal_reward += rewardupdate_model(policy_net, target_net, optimizer, replay_buffer, batch_size, gamma)if done:print(f"Episode {episode + 1}/{num_episodes}, Total Reward: {total_reward}")breakepsilon = max(epsilon_end, epsilon_decay * epsilon)if episode % 10 == 0:target_net.load_state_dict(policy_net.state_dict())return policy_net# 在源环境(CartPole)中训练模型
policy_net_cartpole = train_dqn(env_name='CartPole-v1')
接下来,我们将CartPole-v1环境中训练好的模型迁移到MountainCar-v0环境中,并进行微调。以下是代码示例:
# 定义函数以匹配网络的结构,进行部分权重的迁移
def transfer_weights(policy_net, target_env_state_dim, target_env_action_dim):# 获取预训练的网络pretrained_dict = policy_net.state_dict()# 创建新网络,适应目标环境的状态和动作维度new_policy_net = QNetwork(target_env_state_dim, target_env_action_dim)# 获取新网络的权重new_dict = new_policy_net.state_dict()# 仅保留在预训练网络和新网络中都有的层(即隐藏层的参数)pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in new_dict and 'fc1' not in k and 'fc3' not in k}# 更新新网络的权重new_dict.update(pretrained_dict)# 将更新后的字典加载到新模型中new_policy_net.load_state_dict(new_dict)return new_policy_net# 微调模型
def fine_tune_dqn(policy_net, env_name, num_episodes=200, gamma=0.99, epsilon_start=0.1, epsilon_end=0.01, epsilon_decay=0.995, batch_size=64):env = gym.make(env_name)target_state_dim = env.observation_space.shape[0]target_action_dim = env.action_space.n# 调用 transfer_weights 函数,将权重从 CartPole 模型迁移到新的 MountainCar 模型policy_net = transfer_weights(policy_net, target_state_dim, target_action_dim)target_net = QNetwork(target_state_dim, target_action_dim)target_net.load_state_dict(policy_net.state_dict())target_net.eval()optimizer = optim.Adam(policy_net.parameters())replay_buffer = ReplayBuffer(10000)epsilon = epsilon_startfor episode in range(num_episodes):state, _ = env.reset()total_reward = 0while True:action = select_action(state, policy_net, epsilon, target_action_dim)next_state, reward, done, _, __ = env.step(action)replay_buffer.add((state, action, reward, next_state, done))state = next_statetotal_reward += rewardupdate_model(policy_net, target_net, optimizer, replay_buffer, batch_size, gamma)if done:print(f"Episode {episode + 1}/{num_episodes}, Total Reward: {total_reward}")breakepsilon = max(epsilon_end, epsilon_decay * epsilon)if episode % 10 == 0:target_net.load_state_dict(policy_net.state_dict())return policy_net# 微调源环境训练的策略网络到目标环境 MountainCar
fine_tuned_policy_net = fine_tune_dqn(policy_net_cartpole, env_name='MountainCar-v0')
强学迁移中哪些没有变?
在强化学习的迁移学习过程中,即使经过微调,也存在一些保持不变的部分,这些部分是迁移学习能够有效工作的关键。以下是保持不变的主要内容:
-
隐藏层的结构和部分权重
在迁移学习中,通常会保留预训练模型的隐藏层结构和部分权重。这些隐藏层在源任务中已经学习到了一些通用的特征表示,这些特征在目标任务中可能仍然有用。例如:隐藏层的权重:在预训练模型中,隐藏层的权重已经通过大量的数据训练得到了优化。这些权重在迁移到新任务时会被保留,作为新模型的初始化权重。虽然在微调过程中这些权重可能会发生一些变化,但它们的初始值仍然是预训练模型中的值。
隐藏层的结构:隐藏层的结构(如层数、每层的神经元数量等)通常保持不变,因为这些结构在源任务中已经被证明是有效的。 -
学习算法和框架
迁移学习过程中,学习算法和整体框架通常保持不变。这意味着:算法类型:使用的强化学习算法(如DQN、PPO等)在迁移过程中保持不变。这是因为算法的核心思想和机制适用于多个任务。
框架和超参数:虽然某些超参数(如学习率、折扣因子等)可能需要根据新任务进行调整,但整体的算法框架和大部分超参数保持不变。 -
通用的特征表示
隐藏层学习到的特征表示在迁移过程中保持相对稳定。这些特征表示是数据的通用特征,能够在多个任务中发挥作用。例如:低级特征:在视觉任务中,卷积神经网络的低级层通常学习到边缘、纹理等通用特征,这些特征在不同的视觉任务中都可能有用。
状态空间的通用表示:在强化学习中,隐藏层可能学习到状态空间的通用表示,这些表示在不同的任务中仍然可以提供有用的信息。 -
目标函数的形式
虽然具体的目标函数(如奖励函数)可能因任务而异,但目标函数的形式通常保持不变。强化学习的目标是最大化累积奖励,这一目标形式在迁移学习中仍然适用。例如:最大化累积奖励:无论是源任务还是目标任务,强化学习的目标都是通过学习策略来最大化累积奖励。这一目标形式在迁移过程中保持不变。
奖励函数的形式:虽然奖励的具体定义可能不同,但奖励函数的形式(如即时奖励与累积奖励的关系)通常保持一致。 -
交互机制
强化学习的核心是通过与环境的交互来学习策略。这种交互机制在迁移学习中保持不变:环境交互:在源任务和目标任务中,智能体都需要通过与环境的交互来获取反馈(如奖励和状态转移)。这种交互机制在迁移过程中保持一致。
探索与利用的平衡:在迁移学习中,智能体仍然需要在探索新的策略和利用已知的策略之间进行平衡。这种平衡机制在迁移过程中保持不变。 -
策略网络的输出层结构
虽然输出层的权重可能会根据目标任务进行调整,但输出层的结构(如输出维度)通常保持不变。这是因为输出层的结构是由任务的性质决定的,例如动作空间的维度。
举例说明
假设我们在CartPole-v1环境中训练了一个DQN模型,并将其迁移到MountainCar-v0环境中进行微调。以下是保持不变的部分:隐藏层结构和部分权重:隐藏层的结构和部分权重从CartPole-v1模型迁移到MountainCar-v0模型中。
DQN算法框架:使用的DQN算法框架保持不变,包括经验回放、目标网络等机制。
通用特征表示:隐藏层学习到的通用特征表示(如状态的低级特征)在MountainCar-v0环境中仍然有用。
目标函数形式:最大化累积奖励的目标函数形式保持不变。
交互机制:智能体通过与环境的交互来学习策略的机制保持不变。
通过保持这些部分不变,强化学习的迁移学习能够利用预训练模型的经验,加速在新任务中的学习过程,并提高学习效率和性能。